4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
13 // was in Composite Element!??!?!
17 var E = Roo.lib.Event;
20 // local style camelizing for speed
22 var camelRe = /(-[a-z])/gi;
23 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
24 var view = document.defaultView;
28 * Represents an Element in the DOM.<br><br>
31 var el = Roo.get("my-div");
34 var el = getEl("my-div");
36 // or with a DOM element
37 var el = Roo.get(myDivElement);
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:
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
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:
55 var el = Roo.get("my-div");
61 el.setWidth(100, true);
63 // animation with some options set
70 // using the "anim" property to get the Anim object
76 el.setWidth(100, opt);
78 if(opt.anim.isAnimated()){
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).
88 Roo.Element = function(element, forceNew){
89 var dom = typeof element == "string" ?
90 document.getElementById(element) : element;
91 if(!dom){ // invalid id/element
95 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
96 return Roo.Element.cache[id];
109 this.id = id || Roo.id(dom);
112 var El = Roo.Element;
116 * The element's default display mode (defaults to "")
119 originalDisplay : "",
123 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
129 * Sets the element's visibility mode. When setVisible() is called it
130 * will use this to determine whether to set the visibility or the display property.
131 * @param visMode Element.VISIBILITY or Element.DISPLAY
132 * @return {Roo.Element} this
134 setVisibilityMode : function(visMode){
135 this.visibilityMode = visMode;
139 * Convenience method for setVisibilityMode(Element.DISPLAY)
140 * @param {String} display (optional) What to set display to when visible
141 * @return {Roo.Element} this
143 enableDisplayMode : function(display){
144 this.setVisibilityMode(El.DISPLAY);
145 if(typeof display != "undefined") { this.originalDisplay = display; }
150 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
151 * @param {String} selector The simple selector to test
152 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
153 search as a number or element (defaults to 10 || document.body)
154 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
155 * @return {HTMLElement} The matching DOM node (or null if no match was found)
157 findParent : function(simpleSelector, maxDepth, returnEl){
158 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
159 maxDepth = maxDepth || 50;
160 if(typeof maxDepth != "number"){
161 stopEl = Roo.getDom(maxDepth);
164 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
165 if(dq.is(p, simpleSelector)){
166 return returnEl ? Roo.get(p) : p;
176 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
177 * @param {String} selector The simple selector to test
178 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
179 search as a number or element (defaults to 10 || document.body)
180 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
181 * @return {HTMLElement} The matching DOM node (or null if no match was found)
183 findParentNode : function(simpleSelector, maxDepth, returnEl){
184 var p = Roo.fly(this.dom.parentNode, '_internal');
185 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
189 * Looks at the scrollable parent element
191 findScrollableParent : function(){
193 var el = Roo.get(this.dom.parentNode);
198 !el.isScrollable() ||
202 D.getViewHeight() - el.dom.clientHeight > 15 ||
203 D.getViewWidth() - el.dom.clientWidth > 15
207 el.dom.nodeName.toLowerCase() != 'body'
209 el = Roo.get(el.dom.parentNode);
212 if(!el.isScrollable()){
220 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
221 * This is a shortcut for findParentNode() that always returns an Roo.Element.
222 * @param {String} selector The simple selector to test
223 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
224 search as a number or element (defaults to 10 || document.body)
225 * @return {Roo.Element} The matching DOM node (or null if no match was found)
227 up : function(simpleSelector, maxDepth){
228 return this.findParentNode(simpleSelector, maxDepth, true);
234 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
235 * @param {String} selector The simple selector to test
236 * @return {Boolean} True if this element matches the selector, else false
238 is : function(simpleSelector){
239 return Roo.DomQuery.is(this.dom, simpleSelector);
243 * Perform animation on this element.
244 * @param {Object} args The YUI animation control args
245 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
246 * @param {Function} onComplete (optional) Function to call when animation completes
247 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
248 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
249 * @return {Roo.Element} this
251 animate : function(args, duration, onComplete, easing, animType){
252 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
257 * @private Internal animation call
259 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
260 animType = animType || 'run';
262 var anim = Roo.lib.Anim[animType](
264 (opt.duration || defaultDur) || .35,
265 (opt.easing || defaultEase) || 'easeOut',
267 Roo.callback(cb, this);
268 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
276 // private legacy anim prep
277 preanim : function(a, i){
278 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
282 * Removes worthless text nodes
283 * @param {Boolean} forceReclean (optional) By default the element
284 * keeps track if it has been cleaned already so
285 * you can call this over and over. However, if you update the element and
286 * need to force a reclean, you can pass true.
288 clean : function(forceReclean){
289 if(this.isCleaned && forceReclean !== true){
293 var d = this.dom, n = d.firstChild, ni = -1;
295 var nx = n.nextSibling;
296 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
303 this.isCleaned = true;
308 calcOffsetsTo : function(el){
311 var restorePos = false;
312 if(el.getStyle('position') == 'static'){
313 el.position('relative');
318 while(op && op != d && op.tagName != 'HTML'){
321 op = op.offsetParent;
324 el.position('static');
330 * Scrolls this element into view within the passed container.
331 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
332 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
333 * @return {Roo.Element} this
335 scrollIntoView : function(container, hscroll){
336 var c = Roo.getDom(container) || document.body;
339 var o = this.calcOffsetsTo(c),
342 b = t+el.offsetHeight,
343 r = l+el.offsetWidth;
345 Roo.log([o, l, t, b,r]);
346 Roo.log([el.offsetHeight, el.offsetWidth]);
348 var ch = c.clientHeight;
349 var ct = parseInt(c.scrollTop, 10);
350 var cl = parseInt(c.scrollLeft, 10);
352 var cr = cl + c.clientWidth;
354 Roo.log([ch, ct, cl, cb, cr])
362 if(hscroll !== false){
366 c.scrollLeft = r-c.clientWidth;
373 scrollChildIntoView : function(child, hscroll){
374 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
378 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
379 * the new height may not be available immediately.
380 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
381 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
382 * @param {Function} onComplete (optional) Function to call when animation completes
383 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
384 * @return {Roo.Element} this
386 autoHeight : function(animate, duration, onComplete, easing){
387 var oldHeight = this.getHeight();
389 this.setHeight(1); // force clipping
390 setTimeout(function(){
391 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
393 this.setHeight(height);
395 if(typeof onComplete == "function"){
399 this.setHeight(oldHeight); // restore original height
400 this.setHeight(height, animate, duration, function(){
402 if(typeof onComplete == "function") { onComplete(); }
403 }.createDelegate(this), easing);
405 }.createDelegate(this), 0);
410 * Returns true if this element is an ancestor of the passed element
411 * @param {HTMLElement/String} el The element to check
412 * @return {Boolean} True if this element is an ancestor of el, else false
414 contains : function(el){
415 if(!el){return false;}
416 return D.isAncestor(this.dom, el.dom ? el.dom : el);
420 * Checks whether the element is currently visible using both visibility and display properties.
421 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
422 * @return {Boolean} True if the element is currently visible, else false
424 isVisible : function(deep) {
425 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
426 if(deep !== true || !vis){
429 var p = this.dom.parentNode;
430 while(p && p.tagName.toLowerCase() != "body"){
431 if(!Roo.fly(p, '_isVisible').isVisible()){
440 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
441 * @param {String} selector The CSS selector
442 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
443 * @return {CompositeElement/CompositeElementLite} The composite element
445 select : function(selector, unique){
446 return El.select(selector, unique, this.dom);
450 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
451 * @param {String} selector The CSS selector
452 * @return {Array} An array of the matched nodes
454 query : function(selector, unique){
455 return Roo.DomQuery.select(selector, this.dom);
459 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
460 * @param {String} selector The CSS selector
461 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
462 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
464 child : function(selector, returnDom){
465 var n = Roo.DomQuery.selectNode(selector, this.dom);
466 return returnDom ? n : Roo.get(n);
470 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
471 * @param {String} selector The CSS selector
472 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
473 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
475 down : function(selector, returnDom){
476 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
477 return returnDom ? n : Roo.get(n);
481 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
482 * @param {String} group The group the DD object is member of
483 * @param {Object} config The DD config object
484 * @param {Object} overrides An object containing methods to override/implement on the DD object
485 * @return {Roo.dd.DD} The DD object
487 initDD : function(group, config, overrides){
488 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
489 return Roo.apply(dd, overrides);
493 * Initializes a {@link Roo.dd.DDProxy} object for this element.
494 * @param {String} group The group the DDProxy object is member of
495 * @param {Object} config The DDProxy config object
496 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
497 * @return {Roo.dd.DDProxy} The DDProxy object
499 initDDProxy : function(group, config, overrides){
500 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
501 return Roo.apply(dd, overrides);
505 * Initializes a {@link Roo.dd.DDTarget} object for this element.
506 * @param {String} group The group the DDTarget object is member of
507 * @param {Object} config The DDTarget config object
508 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
509 * @return {Roo.dd.DDTarget} The DDTarget object
511 initDDTarget : function(group, config, overrides){
512 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
513 return Roo.apply(dd, overrides);
517 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
518 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
519 * @param {Boolean} visible Whether the element is visible
520 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
521 * @return {Roo.Element} this
523 setVisible : function(visible, animate){
525 if(this.visibilityMode == El.DISPLAY){
526 this.setDisplayed(visible);
529 this.dom.style.visibility = visible ? "visible" : "hidden";
532 // closure for composites
534 var visMode = this.visibilityMode;
536 this.setOpacity(.01);
537 this.setVisible(true);
539 this.anim({opacity: { to: (visible?1:0) }},
540 this.preanim(arguments, 1),
541 null, .35, 'easeIn', function(){
543 if(visMode == El.DISPLAY){
544 dom.style.display = "none";
546 dom.style.visibility = "hidden";
548 Roo.get(dom).setOpacity(1);
556 * Returns true if display is not "none"
559 isDisplayed : function() {
560 return this.getStyle("display") != "none";
564 * Toggles the element's visibility or display, depending on visibility mode.
565 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
566 * @return {Roo.Element} this
568 toggle : function(animate){
569 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
574 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
575 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
576 * @return {Roo.Element} this
578 setDisplayed : function(value) {
579 if(typeof value == "boolean"){
580 value = value ? this.originalDisplay : "none";
582 this.setStyle("display", value);
587 * Tries to focus the element. Any exceptions are caught and ignored.
588 * @return {Roo.Element} this
598 * Tries to blur the element. Any exceptions are caught and ignored.
599 * @return {Roo.Element} this
609 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
610 * @param {String/Array} className The CSS class to add, or an array of classes
611 * @return {Roo.Element} this
613 addClass : function(className){
614 if(className instanceof Array){
615 for(var i = 0, len = className.length; i < len; i++) {
616 this.addClass(className[i]);
619 if(className && !this.hasClass(className)){
620 this.dom.className = this.dom.className + " " + className;
627 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
628 * @param {String/Array} className The CSS class to add, or an array of classes
629 * @return {Roo.Element} this
631 radioClass : function(className){
632 var siblings = this.dom.parentNode.childNodes;
633 for(var i = 0; i < siblings.length; i++) {
636 Roo.get(s).removeClass(className);
639 this.addClass(className);
644 * Removes one or more CSS classes from the element.
645 * @param {String/Array} className The CSS class to remove, or an array of classes
646 * @return {Roo.Element} this
648 removeClass : function(className){
649 if(!className || !this.dom.className){
652 if(className instanceof Array){
653 for(var i = 0, len = className.length; i < len; i++) {
654 this.removeClass(className[i]);
657 if(this.hasClass(className)){
658 var re = this.classReCache[className];
660 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
661 this.classReCache[className] = re;
664 this.dom.className.replace(re, " ");
674 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
675 * @param {String} className The CSS class to toggle
676 * @return {Roo.Element} this
678 toggleClass : function(className){
679 if(this.hasClass(className)){
680 this.removeClass(className);
682 this.addClass(className);
688 * Checks if the specified CSS class exists on this element's DOM node.
689 * @param {String} className The CSS class to check for
690 * @return {Boolean} True if the class exists, else false
692 hasClass : function(className){
693 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
697 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
698 * @param {String} oldClassName The CSS class to replace
699 * @param {String} newClassName The replacement CSS class
700 * @return {Roo.Element} this
702 replaceClass : function(oldClassName, newClassName){
703 this.removeClass(oldClassName);
704 this.addClass(newClassName);
709 * Returns an object with properties matching the styles requested.
710 * For example, el.getStyles('color', 'font-size', 'width') might return
711 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
712 * @param {String} style1 A style name
713 * @param {String} style2 A style name
714 * @param {String} etc.
715 * @return {Object} The style object
717 getStyles : function(){
718 var a = arguments, len = a.length, r = {};
719 for(var i = 0; i < len; i++){
720 r[a[i]] = this.getStyle(a[i]);
726 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
727 * @param {String} property The style property whose value is returned.
728 * @return {String} The current value of the style property for this element.
730 getStyle : function(){
731 return view && view.getComputedStyle ?
733 var el = this.dom, v, cs, camel;
737 if(el.style && (v = el.style[prop])){
740 if(cs = view.getComputedStyle(el, "")){
741 if(!(camel = propCache[prop])){
742 camel = propCache[prop] = prop.replace(camelRe, camelFn);
749 var el = this.dom, v, cs, camel;
750 if(prop == 'opacity'){
751 if(typeof el.style.filter == 'string'){
752 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
754 var fv = parseFloat(m[1]);
756 return fv ? fv / 100 : 0;
761 }else if(prop == 'float'){
764 if(!(camel = propCache[prop])){
765 camel = propCache[prop] = prop.replace(camelRe, camelFn);
767 if(v = el.style[camel]){
770 if(cs = el.currentStyle){
778 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
779 * @param {String/Object} property The style property to be set, or an object of multiple styles.
780 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
781 * @return {Roo.Element} this
783 setStyle : function(prop, value){
784 if(typeof prop == "string"){
786 if (prop == 'float') {
787 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
792 if(!(camel = propCache[prop])){
793 camel = propCache[prop] = prop.replace(camelRe, camelFn);
796 if(camel == 'opacity') {
797 this.setOpacity(value);
799 this.dom.style[camel] = value;
802 for(var style in prop){
803 if(typeof prop[style] != "function"){
804 this.setStyle(style, prop[style]);
812 * More flexible version of {@link #setStyle} for setting style properties.
813 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
814 * a function which returns such a specification.
815 * @return {Roo.Element} this
817 applyStyles : function(style){
818 Roo.DomHelper.applyStyles(this.dom, style);
823 * 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).
824 * @return {Number} The X position of the element
827 return D.getX(this.dom);
831 * 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).
832 * @return {Number} The Y position of the element
835 return D.getY(this.dom);
839 * 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).
840 * @return {Array} The XY position of the element
843 return D.getXY(this.dom);
847 * 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).
848 * @param {Number} The X position of the element
849 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
850 * @return {Roo.Element} this
852 setX : function(x, animate){
856 this.setXY([x, this.getY()], this.preanim(arguments, 1));
862 * 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).
863 * @param {Number} The Y position of the element
864 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
865 * @return {Roo.Element} this
867 setY : function(y, animate){
871 this.setXY([this.getX(), y], this.preanim(arguments, 1));
877 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
878 * @param {String} left The left CSS property value
879 * @return {Roo.Element} this
881 setLeft : function(left){
882 this.setStyle("left", this.addUnits(left));
887 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
888 * @param {String} top The top CSS property value
889 * @return {Roo.Element} this
891 setTop : function(top){
892 this.setStyle("top", this.addUnits(top));
897 * Sets the element's CSS right style.
898 * @param {String} right The right CSS property value
899 * @return {Roo.Element} this
901 setRight : function(right){
902 this.setStyle("right", this.addUnits(right));
907 * Sets the element's CSS bottom style.
908 * @param {String} bottom The bottom CSS property value
909 * @return {Roo.Element} this
911 setBottom : function(bottom){
912 this.setStyle("bottom", this.addUnits(bottom));
917 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
918 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
919 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
920 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
921 * @return {Roo.Element} this
923 setXY : function(pos, animate){
925 D.setXY(this.dom, pos);
927 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
933 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
934 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
935 * @param {Number} x X value for new position (coordinates are page-based)
936 * @param {Number} y Y value for new position (coordinates are page-based)
937 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
938 * @return {Roo.Element} this
940 setLocation : function(x, y, animate){
941 this.setXY([x, y], this.preanim(arguments, 2));
946 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
947 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
948 * @param {Number} x X value for new position (coordinates are page-based)
949 * @param {Number} y Y value for new position (coordinates are page-based)
950 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
951 * @return {Roo.Element} this
953 moveTo : function(x, y, animate){
954 this.setXY([x, y], this.preanim(arguments, 2));
959 * Returns the region of the given element.
960 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
961 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
963 getRegion : function(){
964 return D.getRegion(this.dom);
968 * Returns the offset height of the element
969 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
970 * @return {Number} The element's height
972 getHeight : function(contentHeight){
973 var h = this.dom.offsetHeight || 0;
974 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
978 * Returns the offset width of the element
979 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
980 * @return {Number} The element's width
982 getWidth : function(contentWidth){
983 var w = this.dom.offsetWidth || 0;
984 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
988 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
989 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
990 * if a height has not been set using CSS.
993 getComputedHeight : function(){
994 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
996 h = parseInt(this.getStyle('height'), 10) || 0;
997 if(!this.isBorderBox()){
998 h += this.getFrameWidth('tb');
1005 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1006 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1007 * if a width has not been set using CSS.
1010 getComputedWidth : function(){
1011 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1013 w = parseInt(this.getStyle('width'), 10) || 0;
1014 if(!this.isBorderBox()){
1015 w += this.getFrameWidth('lr');
1022 * Returns the size of the element.
1023 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1024 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1026 getSize : function(contentSize){
1027 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1031 * Returns the width and height of the viewport.
1032 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1034 getViewSize : function(){
1035 var d = this.dom, doc = document, aw = 0, ah = 0;
1036 if(d == doc || d == doc.body){
1037 return {width : D.getViewWidth(), height: D.getViewHeight()};
1040 width : d.clientWidth,
1041 height: d.clientHeight
1047 * Returns the value of the "value" attribute
1048 * @param {Boolean} asNumber true to parse the value as a number
1049 * @return {String/Number}
1051 getValue : function(asNumber){
1052 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1056 adjustWidth : function(width){
1057 if(typeof width == "number"){
1058 if(this.autoBoxAdjust && !this.isBorderBox()){
1059 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1069 adjustHeight : function(height){
1070 if(typeof height == "number"){
1071 if(this.autoBoxAdjust && !this.isBorderBox()){
1072 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1082 * Set the width of the element
1083 * @param {Number} width The new width
1084 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1085 * @return {Roo.Element} this
1087 setWidth : function(width, animate){
1088 width = this.adjustWidth(width);
1090 this.dom.style.width = this.addUnits(width);
1092 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1098 * Set the height of the element
1099 * @param {Number} height The new height
1100 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1101 * @return {Roo.Element} this
1103 setHeight : function(height, animate){
1104 height = this.adjustHeight(height);
1106 this.dom.style.height = this.addUnits(height);
1108 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1114 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1115 * @param {Number} width The new width
1116 * @param {Number} height The new height
1117 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1118 * @return {Roo.Element} this
1120 setSize : function(width, height, animate){
1121 if(typeof width == "object"){ // in case of object from getSize()
1122 height = width.height; width = width.width;
1124 width = this.adjustWidth(width); height = this.adjustHeight(height);
1126 this.dom.style.width = this.addUnits(width);
1127 this.dom.style.height = this.addUnits(height);
1129 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1135 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1136 * @param {Number} x X value for new position (coordinates are page-based)
1137 * @param {Number} y Y value for new position (coordinates are page-based)
1138 * @param {Number} width The new width
1139 * @param {Number} height The new height
1140 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1141 * @return {Roo.Element} this
1143 setBounds : function(x, y, width, height, animate){
1145 this.setSize(width, height);
1146 this.setLocation(x, y);
1148 width = this.adjustWidth(width); height = this.adjustHeight(height);
1149 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1150 this.preanim(arguments, 4), 'motion');
1156 * 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.
1157 * @param {Roo.lib.Region} region The region to fill
1158 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1159 * @return {Roo.Element} this
1161 setRegion : function(region, animate){
1162 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1167 * Appends an event handler
1169 * @param {String} eventName The type of event to append
1170 * @param {Function} fn The method the event invokes
1171 * @param {Object} scope (optional) The scope (this object) of the fn
1172 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1174 addListener : function(eventName, fn, scope, options){
1176 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1181 * Removes an event handler from this element
1182 * @param {String} eventName the type of event to remove
1183 * @param {Function} fn the method the event invokes
1184 * @return {Roo.Element} this
1186 removeListener : function(eventName, fn){
1187 Roo.EventManager.removeListener(this.dom, eventName, fn);
1192 * Removes all previous added listeners from this element
1193 * @return {Roo.Element} this
1195 removeAllListeners : function(){
1196 E.purgeElement(this.dom);
1200 relayEvent : function(eventName, observable){
1201 this.on(eventName, function(e){
1202 observable.fireEvent(eventName, e);
1207 * Set the opacity of the element
1208 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1209 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1210 * @return {Roo.Element} this
1212 setOpacity : function(opacity, animate){
1214 var s = this.dom.style;
1217 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1218 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1220 s.opacity = opacity;
1223 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1229 * Gets the left X coordinate
1230 * @param {Boolean} local True to get the local css position instead of page coordinate
1233 getLeft : function(local){
1237 return parseInt(this.getStyle("left"), 10) || 0;
1242 * Gets the right X coordinate of the element (element X position + element width)
1243 * @param {Boolean} local True to get the local css position instead of page coordinate
1246 getRight : function(local){
1248 return this.getX() + this.getWidth();
1250 return (this.getLeft(true) + this.getWidth()) || 0;
1255 * Gets the top Y coordinate
1256 * @param {Boolean} local True to get the local css position instead of page coordinate
1259 getTop : function(local) {
1263 return parseInt(this.getStyle("top"), 10) || 0;
1268 * Gets the bottom Y coordinate of the element (element Y position + element height)
1269 * @param {Boolean} local True to get the local css position instead of page coordinate
1272 getBottom : function(local){
1274 return this.getY() + this.getHeight();
1276 return (this.getTop(true) + this.getHeight()) || 0;
1281 * Initializes positioning on this element. If a desired position is not passed, it will make the
1282 * the element positioned relative IF it is not already positioned.
1283 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1284 * @param {Number} zIndex (optional) The zIndex to apply
1285 * @param {Number} x (optional) Set the page X position
1286 * @param {Number} y (optional) Set the page Y position
1288 position : function(pos, zIndex, x, y){
1290 if(this.getStyle('position') == 'static'){
1291 this.setStyle('position', 'relative');
1294 this.setStyle("position", pos);
1297 this.setStyle("z-index", zIndex);
1299 if(x !== undefined && y !== undefined){
1301 }else if(x !== undefined){
1303 }else if(y !== undefined){
1309 * Clear positioning back to the default when the document was loaded
1310 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1311 * @return {Roo.Element} this
1313 clearPositioning : function(value){
1321 "position" : "static"
1327 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1328 * snapshot before performing an update and then restoring the element.
1331 getPositioning : function(){
1332 var l = this.getStyle("left");
1333 var t = this.getStyle("top");
1335 "position" : this.getStyle("position"),
1337 "right" : l ? "" : this.getStyle("right"),
1339 "bottom" : t ? "" : this.getStyle("bottom"),
1340 "z-index" : this.getStyle("z-index")
1345 * Gets the width of the border(s) for the specified side(s)
1346 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1347 * passing lr would get the border (l)eft width + the border (r)ight width.
1348 * @return {Number} The width of the sides passed added together
1350 getBorderWidth : function(side){
1351 return this.addStyles(side, El.borders);
1355 * Gets the width of the padding(s) for the specified side(s)
1356 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1357 * passing lr would get the padding (l)eft + the padding (r)ight.
1358 * @return {Number} The padding of the sides passed added together
1360 getPadding : function(side){
1361 return this.addStyles(side, El.paddings);
1365 * Set positioning with an object returned by getPositioning().
1366 * @param {Object} posCfg
1367 * @return {Roo.Element} this
1369 setPositioning : function(pc){
1370 this.applyStyles(pc);
1371 if(pc.right == "auto"){
1372 this.dom.style.right = "";
1374 if(pc.bottom == "auto"){
1375 this.dom.style.bottom = "";
1381 fixDisplay : function(){
1382 if(this.getStyle("display") == "none"){
1383 this.setStyle("visibility", "hidden");
1384 this.setStyle("display", this.originalDisplay); // first try reverting to default
1385 if(this.getStyle("display") == "none"){ // if that fails, default to block
1386 this.setStyle("display", "block");
1392 * Quick set left and top adding default units
1393 * @param {String} left The left CSS property value
1394 * @param {String} top The top CSS property value
1395 * @return {Roo.Element} this
1397 setLeftTop : function(left, top){
1398 this.dom.style.left = this.addUnits(left);
1399 this.dom.style.top = this.addUnits(top);
1404 * Move this element relative to its current position.
1405 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1406 * @param {Number} distance How far to move the element in pixels
1407 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1408 * @return {Roo.Element} this
1410 move : function(direction, distance, animate){
1411 var xy = this.getXY();
1412 direction = direction.toLowerCase();
1416 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1420 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1425 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1430 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1437 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1438 * @return {Roo.Element} this
1441 if(!this.isClipped){
1442 this.isClipped = true;
1443 this.originalClip = {
1444 "o": this.getStyle("overflow"),
1445 "x": this.getStyle("overflow-x"),
1446 "y": this.getStyle("overflow-y")
1448 this.setStyle("overflow", "hidden");
1449 this.setStyle("overflow-x", "hidden");
1450 this.setStyle("overflow-y", "hidden");
1456 * Return clipping (overflow) to original clipping before clip() was called
1457 * @return {Roo.Element} this
1459 unclip : function(){
1461 this.isClipped = false;
1462 var o = this.originalClip;
1463 if(o.o){this.setStyle("overflow", o.o);}
1464 if(o.x){this.setStyle("overflow-x", o.x);}
1465 if(o.y){this.setStyle("overflow-y", o.y);}
1472 * Gets the x,y coordinates specified by the anchor position on the element.
1473 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1474 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1475 * {width: (target width), height: (target height)} (defaults to the element's current size)
1476 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1477 * @return {Array} [x, y] An array containing the element's x and y coordinates
1479 getAnchorXY : function(anchor, local, s){
1480 //Passing a different size is useful for pre-calculating anchors,
1481 //especially for anchored animations that change the el size.
1483 var w, h, vp = false;
1486 if(d == document.body || d == document){
1488 w = D.getViewWidth(); h = D.getViewHeight();
1490 w = this.getWidth(); h = this.getHeight();
1493 w = s.width; h = s.height;
1495 var x = 0, y = 0, r = Math.round;
1496 switch((anchor || "tl").toLowerCase()){
1538 var sc = this.getScroll();
1539 return [x + sc.left, y + sc.top];
1541 //Add the element's offset xy
1542 var o = this.getXY();
1543 return [x+o[0], y+o[1]];
1547 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1548 * supported position values.
1549 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1550 * @param {String} position The position to align to.
1551 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1552 * @return {Array} [x, y]
1554 getAlignToXY : function(el, p, o){
1558 throw "Element.alignTo with an element that doesn't exist";
1560 var c = false; //constrain to viewport
1561 var p1 = "", p2 = "";
1568 }else if(p.indexOf("-") == -1){
1571 p = p.toLowerCase();
1572 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1574 throw "Element.alignTo with an invalid alignment " + p;
1576 p1 = m[1]; p2 = m[2]; c = !!m[3];
1578 //Subtract the aligned el's internal xy from the target's offset xy
1579 //plus custom offset to get the aligned el's new offset xy
1580 var a1 = this.getAnchorXY(p1, true);
1581 var a2 = el.getAnchorXY(p2, false);
1582 var x = a2[0] - a1[0] + o[0];
1583 var y = a2[1] - a1[1] + o[1];
1585 //constrain the aligned el to viewport if necessary
1586 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1587 // 5px of margin for ie
1588 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1590 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1591 //perpendicular to the vp border, allow the aligned el to slide on that border,
1592 //otherwise swap the aligned el to the opposite border of the target.
1593 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1594 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1595 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1596 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1599 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1600 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1602 if((x+w) > dw + scrollX){
1603 x = swapX ? r.left-w : dw+scrollX-w;
1606 x = swapX ? r.right : scrollX;
1608 if((y+h) > dh + scrollY){
1609 y = swapY ? r.top-h : dh+scrollY-h;
1612 y = swapY ? r.bottom : scrollY;
1619 getConstrainToXY : function(){
1620 var os = {top:0, left:0, bottom:0, right: 0};
1622 return function(el, local, offsets, proposedXY){
1624 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1626 var vw, vh, vx = 0, vy = 0;
1627 if(el.dom == document.body || el.dom == document){
1628 vw = Roo.lib.Dom.getViewWidth();
1629 vh = Roo.lib.Dom.getViewHeight();
1631 vw = el.dom.clientWidth;
1632 vh = el.dom.clientHeight;
1634 var vxy = el.getXY();
1640 var s = el.getScroll();
1642 vx += offsets.left + s.left;
1643 vy += offsets.top + s.top;
1645 vw -= offsets.right;
1646 vh -= offsets.bottom;
1651 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1652 var x = xy[0], y = xy[1];
1653 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1655 // only move it if it needs it
1658 // first validate right/bottom
1667 // then make sure top/left isn't negative
1676 return moved ? [x, y] : false;
1681 adjustForConstraints : function(xy, parent, offsets){
1682 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1686 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1687 * document it aligns it to the viewport.
1688 * The position parameter is optional, and can be specified in any one of the following formats:
1690 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1691 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1692 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1693 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1694 * <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
1695 * element's anchor point, and the second value is used as the target's anchor point.</li>
1697 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1698 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1699 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1700 * that specified in order to enforce the viewport constraints.
1701 * Following are all of the supported anchor positions:
1704 ----- -----------------------------
1705 tl The top left corner (default)
1706 t The center of the top edge
1707 tr The top right corner
1708 l The center of the left edge
1709 c In the center of the element
1710 r The center of the right edge
1711 bl The bottom left corner
1712 b The center of the bottom edge
1713 br The bottom right corner
1717 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1718 el.alignTo("other-el");
1720 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1721 el.alignTo("other-el", "tr?");
1723 // align the bottom right corner of el with the center left edge of other-el
1724 el.alignTo("other-el", "br-l?");
1726 // align the center of el with the bottom left corner of other-el and
1727 // adjust the x position by -6 pixels (and the y position by 0)
1728 el.alignTo("other-el", "c-bl", [-6, 0]);
1730 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1731 * @param {String} position The position to align to.
1732 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1733 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1734 * @return {Roo.Element} this
1736 alignTo : function(element, position, offsets, animate){
1737 var xy = this.getAlignToXY(element, position, offsets);
1738 this.setXY(xy, this.preanim(arguments, 3));
1743 * Anchors an element to another element and realigns it when the window is resized.
1744 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1745 * @param {String} position The position to align to.
1746 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1747 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1748 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1749 * is a number, it is used as the buffer delay (defaults to 50ms).
1750 * @param {Function} callback The function to call after the animation finishes
1751 * @return {Roo.Element} this
1753 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1754 var action = function(){
1755 this.alignTo(el, alignment, offsets, animate);
1756 Roo.callback(callback, this);
1758 Roo.EventManager.onWindowResize(action, this);
1759 var tm = typeof monitorScroll;
1760 if(tm != 'undefined'){
1761 Roo.EventManager.on(window, 'scroll', action, this,
1762 {buffer: tm == 'number' ? monitorScroll : 50});
1764 action.call(this); // align immediately
1768 * Clears any opacity settings from this element. Required in some cases for IE.
1769 * @return {Roo.Element} this
1771 clearOpacity : function(){
1772 if (window.ActiveXObject) {
1773 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1774 this.dom.style.filter = "";
1777 this.dom.style.opacity = "";
1778 this.dom.style["-moz-opacity"] = "";
1779 this.dom.style["-khtml-opacity"] = "";
1785 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1786 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1787 * @return {Roo.Element} this
1789 hide : function(animate){
1790 this.setVisible(false, this.preanim(arguments, 0));
1795 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1796 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1797 * @return {Roo.Element} this
1799 show : function(animate){
1800 this.setVisible(true, this.preanim(arguments, 0));
1805 * @private Test if size has a unit, otherwise appends the default
1807 addUnits : function(size){
1808 return Roo.Element.addUnits(size, this.defaultUnit);
1812 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1813 * @return {Roo.Element} this
1815 beginMeasure : function(){
1817 if(el.offsetWidth || el.offsetHeight){
1818 return this; // offsets work already
1821 var p = this.dom, b = document.body; // start with this element
1822 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1823 var pe = Roo.get(p);
1824 if(pe.getStyle('display') == 'none'){
1825 changed.push({el: p, visibility: pe.getStyle("visibility")});
1826 p.style.visibility = "hidden";
1827 p.style.display = "block";
1831 this._measureChanged = changed;
1837 * Restores displays to before beginMeasure was called
1838 * @return {Roo.Element} this
1840 endMeasure : function(){
1841 var changed = this._measureChanged;
1843 for(var i = 0, len = changed.length; i < len; i++) {
1845 r.el.style.visibility = r.visibility;
1846 r.el.style.display = "none";
1848 this._measureChanged = null;
1854 * Update the innerHTML of this element, optionally searching for and processing scripts
1855 * @param {String} html The new HTML
1856 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1857 * @param {Function} callback For async script loading you can be noticed when the update completes
1858 * @return {Roo.Element} this
1860 update : function(html, loadScripts, callback){
1861 if(typeof html == "undefined"){
1864 if(loadScripts !== true){
1865 this.dom.innerHTML = html;
1866 if(typeof callback == "function"){
1874 html += '<span id="' + id + '"></span>';
1876 E.onAvailable(id, function(){
1877 var hd = document.getElementsByTagName("head")[0];
1878 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1879 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1880 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1883 while(match = re.exec(html)){
1884 var attrs = match[1];
1885 var srcMatch = attrs ? attrs.match(srcRe) : false;
1886 if(srcMatch && srcMatch[2]){
1887 var s = document.createElement("script");
1888 s.src = srcMatch[2];
1889 var typeMatch = attrs.match(typeRe);
1890 if(typeMatch && typeMatch[2]){
1891 s.type = typeMatch[2];
1894 }else if(match[2] && match[2].length > 0){
1895 if(window.execScript) {
1896 window.execScript(match[2]);
1904 window.eval(match[2]);
1908 var el = document.getElementById(id);
1909 if(el){el.parentNode.removeChild(el);}
1910 if(typeof callback == "function"){
1914 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1919 * Direct access to the UpdateManager update() method (takes the same parameters).
1920 * @param {String/Function} url The url for this request or a function to call to get the url
1921 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
1922 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1923 * @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.
1924 * @return {Roo.Element} this
1927 var um = this.getUpdateManager();
1928 um.update.apply(um, arguments);
1933 * Gets this element's UpdateManager
1934 * @return {Roo.UpdateManager} The UpdateManager
1936 getUpdateManager : function(){
1937 if(!this.updateManager){
1938 this.updateManager = new Roo.UpdateManager(this);
1940 return this.updateManager;
1944 * Disables text selection for this element (normalized across browsers)
1945 * @return {Roo.Element} this
1947 unselectable : function(){
1948 this.dom.unselectable = "on";
1949 this.swallowEvent("selectstart", true);
1950 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1951 this.addClass("x-unselectable");
1956 * Calculates the x, y to center this element on the screen
1957 * @return {Array} The x, y values [x, y]
1959 getCenterXY : function(){
1960 return this.getAlignToXY(document, 'c-c');
1964 * Centers the Element in either the viewport, or another Element.
1965 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1967 center : function(centerIn){
1968 this.alignTo(centerIn || document, 'c-c');
1973 * Tests various css rules/browsers to determine if this element uses a border box
1976 isBorderBox : function(){
1977 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1981 * Return a box {x, y, width, height} that can be used to set another elements
1982 * size/location to match this element.
1983 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1984 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1985 * @return {Object} box An object in the format {x, y, width, height}
1987 getBox : function(contentBox, local){
1992 var left = parseInt(this.getStyle("left"), 10) || 0;
1993 var top = parseInt(this.getStyle("top"), 10) || 0;
1996 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
1998 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
2000 var l = this.getBorderWidth("l")+this.getPadding("l");
2001 var r = this.getBorderWidth("r")+this.getPadding("r");
2002 var t = this.getBorderWidth("t")+this.getPadding("t");
2003 var b = this.getBorderWidth("b")+this.getPadding("b");
2004 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)};
2006 bx.right = bx.x + bx.width;
2007 bx.bottom = bx.y + bx.height;
2012 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2013 for more information about the sides.
2014 * @param {String} sides
2017 getFrameWidth : function(sides, onlyContentBox){
2018 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2022 * 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.
2023 * @param {Object} box The box to fill {x, y, width, height}
2024 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2025 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2026 * @return {Roo.Element} this
2028 setBox : function(box, adjust, animate){
2029 var w = box.width, h = box.height;
2030 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2031 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2032 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2034 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2039 * Forces the browser to repaint this element
2040 * @return {Roo.Element} this
2042 repaint : function(){
2044 this.addClass("x-repaint");
2045 setTimeout(function(){
2046 Roo.get(dom).removeClass("x-repaint");
2052 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2053 * then it returns the calculated width of the sides (see getPadding)
2054 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2055 * @return {Object/Number}
2057 getMargins : function(side){
2060 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2061 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2062 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2063 right: parseInt(this.getStyle("margin-right"), 10) || 0
2066 return this.addStyles(side, El.margins);
2071 addStyles : function(sides, styles){
2073 for(var i = 0, len = sides.length; i < len; i++){
2074 v = this.getStyle(styles[sides.charAt(i)]);
2076 w = parseInt(v, 10);
2084 * Creates a proxy element of this element
2085 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2086 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2087 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2088 * @return {Roo.Element} The new proxy element
2090 createProxy : function(config, renderTo, matchBox){
2092 renderTo = Roo.getDom(renderTo);
2094 renderTo = document.body;
2096 config = typeof config == "object" ?
2097 config : {tag : "div", cls: config};
2098 var proxy = Roo.DomHelper.append(renderTo, config, true);
2100 proxy.setBox(this.getBox());
2106 * Puts a mask over this element to disable user interaction. Requires core.css.
2107 * This method can only be applied to elements which accept child nodes.
2108 * @param {String} msg (optional) A message to display in the mask
2109 * @param {String} msgCls (optional) A css class to apply to the msg element
2110 * @return {Element} The mask element
2112 mask : function(msg, msgCls)
2114 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2115 this.setStyle("position", "relative");
2118 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2120 this.addClass("x-masked");
2121 this._mask.setDisplayed(true);
2126 while (dom && dom.style) {
2127 if (!isNaN(parseInt(dom.style.zIndex))) {
2128 z = Math.max(z, parseInt(dom.style.zIndex));
2130 dom = dom.parentNode;
2132 // if we are masking the body - then it hides everything..
2133 if (this.dom == document.body) {
2135 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2136 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2139 if(typeof msg == 'string'){
2141 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2143 var mm = this._maskMsg;
2144 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2145 if (mm.dom.firstChild) { // weird IE issue?
2146 mm.dom.firstChild.innerHTML = msg;
2148 mm.setDisplayed(true);
2150 mm.setStyle('z-index', z + 102);
2152 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2153 this._mask.setHeight(this.getHeight());
2155 this._mask.setStyle('z-index', z + 100);
2161 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2162 * it is cached for reuse.
2164 unmask : function(removeEl){
2166 if(removeEl === true){
2167 this._mask.remove();
2170 this._maskMsg.remove();
2171 delete this._maskMsg;
2174 this._mask.setDisplayed(false);
2176 this._maskMsg.setDisplayed(false);
2180 this.removeClass("x-masked");
2184 * Returns true if this element is masked
2187 isMasked : function(){
2188 return this._mask && this._mask.isVisible();
2192 * Creates an iframe shim for this element to keep selects and other windowed objects from
2194 * @return {Roo.Element} The new shim element
2196 createShim : function(){
2197 var el = document.createElement('iframe');
2198 el.frameBorder = 'no';
2199 el.className = 'roo-shim';
2200 if(Roo.isIE && Roo.isSecure){
2201 el.src = Roo.SSL_SECURE_URL;
2203 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2204 shim.autoBoxAdjust = false;
2209 * Removes this element from the DOM and deletes it from the cache
2211 remove : function(){
2212 if(this.dom.parentNode){
2213 this.dom.parentNode.removeChild(this.dom);
2215 delete El.cache[this.dom.id];
2219 * Sets up event handlers to add and remove a css class when the mouse is over this element
2220 * @param {String} className
2221 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2222 * mouseout events for children elements
2223 * @return {Roo.Element} this
2225 addClassOnOver : function(className, preventFlicker){
2226 this.on("mouseover", function(){
2227 Roo.fly(this, '_internal').addClass(className);
2229 var removeFn = function(e){
2230 if(preventFlicker !== true || !e.within(this, true)){
2231 Roo.fly(this, '_internal').removeClass(className);
2234 this.on("mouseout", removeFn, this.dom);
2239 * Sets up event handlers to add and remove a css class when this element has the focus
2240 * @param {String} className
2241 * @return {Roo.Element} this
2243 addClassOnFocus : function(className){
2244 this.on("focus", function(){
2245 Roo.fly(this, '_internal').addClass(className);
2247 this.on("blur", function(){
2248 Roo.fly(this, '_internal').removeClass(className);
2253 * 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)
2254 * @param {String} className
2255 * @return {Roo.Element} this
2257 addClassOnClick : function(className){
2259 this.on("mousedown", function(){
2260 Roo.fly(dom, '_internal').addClass(className);
2261 var d = Roo.get(document);
2262 var fn = function(){
2263 Roo.fly(dom, '_internal').removeClass(className);
2264 d.removeListener("mouseup", fn);
2266 d.on("mouseup", fn);
2272 * Stops the specified event from bubbling and optionally prevents the default action
2273 * @param {String} eventName
2274 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2275 * @return {Roo.Element} this
2277 swallowEvent : function(eventName, preventDefault){
2278 var fn = function(e){
2279 e.stopPropagation();
2284 if(eventName instanceof Array){
2285 for(var i = 0, len = eventName.length; i < len; i++){
2286 this.on(eventName[i], fn);
2290 this.on(eventName, fn);
2297 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2300 * Sizes this element to its parent element's dimensions performing
2301 * neccessary box adjustments.
2302 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2303 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2304 * @return {Roo.Element} this
2306 fitToParent : function(monitorResize, targetParent) {
2307 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2308 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2309 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2312 var p = Roo.get(targetParent || this.dom.parentNode);
2313 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2314 if (monitorResize === true) {
2315 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2316 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2322 * Gets the next sibling, skipping text nodes
2323 * @return {HTMLElement} The next sibling or null
2325 getNextSibling : function(){
2326 var n = this.dom.nextSibling;
2327 while(n && n.nodeType != 1){
2334 * Gets the previous sibling, skipping text nodes
2335 * @return {HTMLElement} The previous sibling or null
2337 getPrevSibling : function(){
2338 var n = this.dom.previousSibling;
2339 while(n && n.nodeType != 1){
2340 n = n.previousSibling;
2347 * Appends the passed element(s) to this element
2348 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2349 * @return {Roo.Element} this
2351 appendChild: function(el){
2358 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2359 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2360 * automatically generated with the specified attributes.
2361 * @param {HTMLElement} insertBefore (optional) a child element of this element
2362 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2363 * @return {Roo.Element} The new child element
2365 createChild: function(config, insertBefore, returnDom){
2366 config = config || {tag:'div'};
2368 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2370 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2374 * Appends this element to the passed element
2375 * @param {String/HTMLElement/Element} el The new parent element
2376 * @return {Roo.Element} this
2378 appendTo: function(el){
2379 el = Roo.getDom(el);
2380 el.appendChild(this.dom);
2385 * Inserts this element before the passed element in the DOM
2386 * @param {String/HTMLElement/Element} el The element to insert before
2387 * @return {Roo.Element} this
2389 insertBefore: function(el){
2390 el = Roo.getDom(el);
2391 el.parentNode.insertBefore(this.dom, el);
2396 * Inserts this element after the passed element in the DOM
2397 * @param {String/HTMLElement/Element} el The element to insert after
2398 * @return {Roo.Element} this
2400 insertAfter: function(el){
2401 el = Roo.getDom(el);
2402 el.parentNode.insertBefore(this.dom, el.nextSibling);
2407 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2408 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2409 * @return {Roo.Element} The new child
2411 insertFirst: function(el, returnDom){
2413 if(typeof el == 'object' && !el.nodeType){ // dh config
2414 return this.createChild(el, this.dom.firstChild, returnDom);
2416 el = Roo.getDom(el);
2417 this.dom.insertBefore(el, this.dom.firstChild);
2418 return !returnDom ? Roo.get(el) : el;
2423 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2424 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2425 * @param {String} where (optional) 'before' or 'after' defaults to before
2426 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2427 * @return {Roo.Element} the inserted Element
2429 insertSibling: function(el, where, returnDom){
2430 where = where ? where.toLowerCase() : 'before';
2432 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2434 if(typeof el == 'object' && !el.nodeType){ // dh config
2435 if(where == 'after' && !this.dom.nextSibling){
2436 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2438 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2442 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2443 where == 'before' ? this.dom : this.dom.nextSibling);
2452 * Creates and wraps this element with another element
2453 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2454 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2455 * @return {HTMLElement/Element} The newly created wrapper element
2457 wrap: function(config, returnDom){
2459 config = {tag: "div"};
2461 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2462 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2467 * Replaces the passed element with this element
2468 * @param {String/HTMLElement/Element} el The element to replace
2469 * @return {Roo.Element} this
2471 replace: function(el){
2473 this.insertBefore(el);
2479 * Inserts an html fragment into this element
2480 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2481 * @param {String} html The HTML fragment
2482 * @param {Boolean} returnEl True to return an Roo.Element
2483 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2485 insertHtml : function(where, html, returnEl){
2486 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2487 return returnEl ? Roo.get(el) : el;
2491 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2492 * @param {Object} o The object with the attributes
2493 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2494 * @return {Roo.Element} this
2496 set : function(o, useSet){
2498 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2500 if(attr == "style" || typeof o[attr] == "function") { continue; }
2502 el.className = o["cls"];
2505 el.setAttribute(attr, o[attr]);
2512 Roo.DomHelper.applyStyles(el, o.style);
2518 * Convenience method for constructing a KeyMap
2519 * @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:
2520 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2521 * @param {Function} fn The function to call
2522 * @param {Object} scope (optional) The scope of the function
2523 * @return {Roo.KeyMap} The KeyMap created
2525 addKeyListener : function(key, fn, scope){
2527 if(typeof key != "object" || key instanceof Array){
2543 return new Roo.KeyMap(this, config);
2547 * Creates a KeyMap for this element
2548 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2549 * @return {Roo.KeyMap} The KeyMap created
2551 addKeyMap : function(config){
2552 return new Roo.KeyMap(this, config);
2556 * Returns true if this element is scrollable.
2559 isScrollable : function(){
2561 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2565 * 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().
2566 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2567 * @param {Number} value The new scroll value
2568 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2569 * @return {Element} this
2572 scrollTo : function(side, value, animate){
2573 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2575 this.dom[prop] = value;
2577 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2578 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2584 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2585 * within this element's scrollable range.
2586 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2587 * @param {Number} distance How far to scroll the element in pixels
2588 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2589 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2590 * was scrolled as far as it could go.
2592 scroll : function(direction, distance, animate){
2593 if(!this.isScrollable()){
2597 var l = el.scrollLeft, t = el.scrollTop;
2598 var w = el.scrollWidth, h = el.scrollHeight;
2599 var cw = el.clientWidth, ch = el.clientHeight;
2600 direction = direction.toLowerCase();
2601 var scrolled = false;
2602 var a = this.preanim(arguments, 2);
2607 var v = Math.min(l + distance, w-cw);
2608 this.scrollTo("left", v, a);
2615 var v = Math.max(l - distance, 0);
2616 this.scrollTo("left", v, a);
2624 var v = Math.max(t - distance, 0);
2625 this.scrollTo("top", v, a);
2633 var v = Math.min(t + distance, h-ch);
2634 this.scrollTo("top", v, a);
2643 * Translates the passed page coordinates into left/top css values for this element
2644 * @param {Number/Array} x The page x or an array containing [x, y]
2645 * @param {Number} y The page y
2646 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2648 translatePoints : function(x, y){
2649 if(typeof x == 'object' || x instanceof Array){
2652 var p = this.getStyle('position');
2653 var o = this.getXY();
2655 var l = parseInt(this.getStyle('left'), 10);
2656 var t = parseInt(this.getStyle('top'), 10);
2659 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2662 t = (p == "relative") ? 0 : this.dom.offsetTop;
2665 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2669 * Returns the current scroll position of the element.
2670 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2672 getScroll : function(){
2673 var d = this.dom, doc = document;
2674 if(d == doc || d == doc.body){
2675 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2676 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2677 return {left: l, top: t};
2679 return {left: d.scrollLeft, top: d.scrollTop};
2684 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2685 * are convert to standard 6 digit hex color.
2686 * @param {String} attr The css attribute
2687 * @param {String} defaultValue The default value to use when a valid color isn't found
2688 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2691 getColor : function(attr, defaultValue, prefix){
2692 var v = this.getStyle(attr);
2693 if(!v || v == "transparent" || v == "inherit") {
2694 return defaultValue;
2696 var color = typeof prefix == "undefined" ? "#" : prefix;
2697 if(v.substr(0, 4) == "rgb("){
2698 var rvs = v.slice(4, v.length -1).split(",");
2699 for(var i = 0; i < 3; i++){
2700 var h = parseInt(rvs[i]).toString(16);
2707 if(v.substr(0, 1) == "#"){
2709 for(var i = 1; i < 4; i++){
2710 var c = v.charAt(i);
2713 }else if(v.length == 7){
2714 color += v.substr(1);
2718 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2722 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2723 * gradient background, rounded corners and a 4-way shadow.
2724 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2725 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2726 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2727 * @return {Roo.Element} this
2729 boxWrap : function(cls){
2730 cls = cls || 'x-box';
2731 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2732 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2737 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2738 * @param {String} namespace The namespace in which to look for the attribute
2739 * @param {String} name The attribute name
2740 * @return {String} The attribute value
2742 getAttributeNS : Roo.isIE ? function(ns, name){
2744 var type = typeof d[ns+":"+name];
2745 if(type != 'undefined' && type != 'unknown'){
2746 return d[ns+":"+name];
2749 } : function(ns, name){
2751 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2756 * Sets or Returns the value the dom attribute value
2757 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2758 * @param {String} value (optional) The value to set the attribute to
2759 * @return {String} The attribute value
2761 attr : function(name){
2762 if (arguments.length > 1) {
2763 this.dom.setAttribute(name, arguments[1]);
2764 return arguments[1];
2766 if (typeof(name) == 'object') {
2767 for(var i in name) {
2768 this.attr(i, name[i]);
2774 if (!this.dom.hasAttribute(name)) {
2777 return this.dom.getAttribute(name);
2784 var ep = El.prototype;
2787 * Appends an event handler (Shorthand for addListener)
2788 * @param {String} eventName The type of event to append
2789 * @param {Function} fn The method the event invokes
2790 * @param {Object} scope (optional) The scope (this object) of the fn
2791 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2794 ep.on = ep.addListener;
2796 ep.mon = ep.addListener;
2799 * Removes an event handler from this element (shorthand for removeListener)
2800 * @param {String} eventName the type of event to remove
2801 * @param {Function} fn the method the event invokes
2802 * @return {Roo.Element} this
2805 ep.un = ep.removeListener;
2808 * true to automatically adjust width and height settings for box-model issues (default to true)
2810 ep.autoBoxAdjust = true;
2813 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2816 El.addUnits = function(v, defaultUnit){
2817 if(v === "" || v == "auto"){
2820 if(v === undefined){
2823 if(typeof v == "number" || !El.unitPattern.test(v)){
2824 return v + (defaultUnit || 'px');
2829 // special markup used throughout Roo when box wrapping elements
2830 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>';
2832 * Visibility mode constant - Use visibility to hide element
2838 * Visibility mode constant - Use display to hide element
2844 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2845 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2846 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2858 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2859 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2860 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2861 * @return {Element} The Element object
2864 El.get = function(el){
2866 if(!el){ return null; }
2867 if(typeof el == "string"){ // element id
2868 if(!(elm = document.getElementById(el))){
2871 if(ex = El.cache[el]){
2874 ex = El.cache[el] = new El(elm);
2877 }else if(el.tagName){ // dom element
2881 if(ex = El.cache[id]){
2884 ex = El.cache[id] = new El(el);
2887 }else if(el instanceof El){
2889 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2890 // catch case where it hasn't been appended
2891 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2894 }else if(el.isComposite){
2896 }else if(el instanceof Array){
2897 return El.select(el);
2898 }else if(el == document){
2899 // create a bogus element object representing the document object
2901 var f = function(){};
2902 f.prototype = El.prototype;
2904 docEl.dom = document;
2912 El.uncache = function(el){
2913 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2915 delete El.cache[a[i].id || a[i]];
2921 // Garbage collection - uncache elements/purge listeners on orphaned elements
2922 // so we don't hold a reference and cause the browser to retain them
2923 El.garbageCollect = function(){
2924 if(!Roo.enableGarbageCollector){
2925 clearInterval(El.collectorThread);
2928 for(var eid in El.cache){
2929 var el = El.cache[eid], d = el.dom;
2930 // -------------------------------------------------------
2931 // Determining what is garbage:
2932 // -------------------------------------------------------
2934 // dom node is null, definitely garbage
2935 // -------------------------------------------------------
2937 // no parentNode == direct orphan, definitely garbage
2938 // -------------------------------------------------------
2939 // !d.offsetParent && !document.getElementById(eid)
2940 // display none elements have no offsetParent so we will
2941 // also try to look it up by it's id. However, check
2942 // offsetParent first so we don't do unneeded lookups.
2943 // This enables collection of elements that are not orphans
2944 // directly, but somewhere up the line they have an orphan
2946 // -------------------------------------------------------
2947 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2948 delete El.cache[eid];
2949 if(d && Roo.enableListenerCollection){
2955 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2959 El.Flyweight = function(dom){
2962 El.Flyweight.prototype = El.prototype;
2964 El._flyweights = {};
2966 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2967 * the dom node can be overwritten by other code.
2968 * @param {String/HTMLElement} el The dom node or id
2969 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2970 * prevent conflicts (e.g. internally Roo uses "_internal")
2972 * @return {Element} The shared Element object
2974 El.fly = function(el, named){
2975 named = named || '_global';
2976 el = Roo.getDom(el);
2980 if(!El._flyweights[named]){
2981 El._flyweights[named] = new El.Flyweight();
2983 El._flyweights[named].dom = el;
2984 return El._flyweights[named];
2988 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2989 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2990 * Shorthand of {@link Roo.Element#get}
2991 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2992 * @return {Element} The Element object
2998 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2999 * the dom node can be overwritten by other code.
3000 * Shorthand of {@link Roo.Element#fly}
3001 * @param {String/HTMLElement} el The dom node or id
3002 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3003 * prevent conflicts (e.g. internally Roo uses "_internal")
3005 * @return {Element} The shared Element object
3011 // speedy lookup for elements never to box adjust
3012 var noBoxAdjust = Roo.isStrict ? {
3015 input:1, select:1, textarea:1
3017 if(Roo.isIE || Roo.isGecko){
3018 noBoxAdjust['button'] = 1;
3022 Roo.EventManager.on(window, 'unload', function(){
3024 delete El._flyweights;
3032 Roo.Element.selectorFunction = Roo.DomQuery.select;
3035 Roo.Element.select = function(selector, unique, root){
3037 if(typeof selector == "string"){
3038 els = Roo.Element.selectorFunction(selector, root);
3039 }else if(selector.length !== undefined){
3042 throw "Invalid selector";
3044 if(unique === true){
3045 return new Roo.CompositeElement(els);
3047 return new Roo.CompositeElementLite(els);
3051 * Selects elements based on the passed CSS selector to enable working on them as 1.
3052 * @param {String/Array} selector The CSS selector or an array of elements
3053 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3054 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3055 * @return {CompositeElementLite/CompositeElement}
3059 Roo.select = Roo.Element.select;