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 overflowRegex = /(auto|scroll)/;
195 if(this.getStyle('position') === 'fixed'){
196 return Roo.get(document.body);
199 var excludeStaticParent = this.getStyle('position') === "absolute";
201 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
203 if (excludeStaticParent && parent.getStyle('position') === "static") {
207 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
212 return Roo.get(document.body);
216 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
217 * This is a shortcut for findParentNode() that always returns an Roo.Element.
218 * @param {String} selector The simple selector to test
219 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
220 search as a number or element (defaults to 10 || document.body)
221 * @return {Roo.Element} The matching DOM node (or null if no match was found)
223 up : function(simpleSelector, maxDepth){
224 return this.findParentNode(simpleSelector, maxDepth, true);
230 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
231 * @param {String} selector The simple selector to test
232 * @return {Boolean} True if this element matches the selector, else false
234 is : function(simpleSelector){
235 return Roo.DomQuery.is(this.dom, simpleSelector);
239 * Perform animation on this element.
240 * @param {Object} args The YUI animation control args
241 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
242 * @param {Function} onComplete (optional) Function to call when animation completes
243 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
244 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
245 * @return {Roo.Element} this
247 animate : function(args, duration, onComplete, easing, animType){
248 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
253 * @private Internal animation call
255 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
256 animType = animType || 'run';
258 var anim = Roo.lib.Anim[animType](
260 (opt.duration || defaultDur) || .35,
261 (opt.easing || defaultEase) || 'easeOut',
263 Roo.callback(cb, this);
264 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
272 // private legacy anim prep
273 preanim : function(a, i){
274 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
278 * Removes worthless text nodes
279 * @param {Boolean} forceReclean (optional) By default the element
280 * keeps track if it has been cleaned already so
281 * you can call this over and over. However, if you update the element and
282 * need to force a reclean, you can pass true.
284 clean : function(forceReclean){
285 if(this.isCleaned && forceReclean !== true){
289 var d = this.dom, n = d.firstChild, ni = -1;
291 var nx = n.nextSibling;
292 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
299 this.isCleaned = true;
304 calcOffsetsTo : function(el){
307 var restorePos = false;
308 if(el.getStyle('position') == 'static'){
309 el.position('relative');
314 while(op && op != d && op.tagName != 'HTML'){
317 op = op.offsetParent;
320 el.position('static');
326 * Scrolls this element into view within the passed container.
327 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
328 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
329 * @return {Roo.Element} this
331 scrollIntoView : function(container, hscroll){
332 var c = Roo.getDom(container) || document.body;
335 var o = this.calcOffsetsTo(c),
338 b = t+el.offsetHeight,
339 r = l+el.offsetWidth;
341 var ch = c.clientHeight;
342 var ct = parseInt(c.scrollTop, 10);
343 var cl = parseInt(c.scrollLeft, 10);
345 var cr = cl + c.clientWidth;
353 if(hscroll !== false){
357 c.scrollLeft = r-c.clientWidth;
364 scrollChildIntoView : function(child, hscroll){
365 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
369 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
370 * the new height may not be available immediately.
371 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
372 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
373 * @param {Function} onComplete (optional) Function to call when animation completes
374 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
375 * @return {Roo.Element} this
377 autoHeight : function(animate, duration, onComplete, easing){
378 var oldHeight = this.getHeight();
380 this.setHeight(1); // force clipping
381 setTimeout(function(){
382 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
384 this.setHeight(height);
386 if(typeof onComplete == "function"){
390 this.setHeight(oldHeight); // restore original height
391 this.setHeight(height, animate, duration, function(){
393 if(typeof onComplete == "function") { onComplete(); }
394 }.createDelegate(this), easing);
396 }.createDelegate(this), 0);
401 * Returns true if this element is an ancestor of the passed element
402 * @param {HTMLElement/String} el The element to check
403 * @return {Boolean} True if this element is an ancestor of el, else false
405 contains : function(el){
406 if(!el){return false;}
407 return D.isAncestor(this.dom, el.dom ? el.dom : el);
411 * Checks whether the element is currently visible using both visibility and display properties.
412 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
413 * @return {Boolean} True if the element is currently visible, else false
415 isVisible : function(deep) {
416 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
417 if(deep !== true || !vis){
420 var p = this.dom.parentNode;
421 while(p && p.tagName.toLowerCase() != "body"){
422 if(!Roo.fly(p, '_isVisible').isVisible()){
431 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
432 * @param {String} selector The CSS selector
433 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
434 * @return {CompositeElement/CompositeElementLite} The composite element
436 select : function(selector, unique){
437 return El.select(selector, unique, this.dom);
441 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
442 * @param {String} selector The CSS selector
443 * @return {Array} An array of the matched nodes
445 query : function(selector, unique){
446 return Roo.DomQuery.select(selector, this.dom);
450 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
451 * @param {String} selector The CSS selector
452 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
453 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
455 child : function(selector, returnDom){
456 var n = Roo.DomQuery.selectNode(selector, this.dom);
457 return returnDom ? n : Roo.get(n);
461 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
462 * @param {String} selector The CSS selector
463 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
464 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
466 down : function(selector, returnDom){
467 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
468 return returnDom ? n : Roo.get(n);
472 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
473 * @param {String} group The group the DD object is member of
474 * @param {Object} config The DD config object
475 * @param {Object} overrides An object containing methods to override/implement on the DD object
476 * @return {Roo.dd.DD} The DD object
478 initDD : function(group, config, overrides){
479 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
480 return Roo.apply(dd, overrides);
484 * Initializes a {@link Roo.dd.DDProxy} object for this element.
485 * @param {String} group The group the DDProxy object is member of
486 * @param {Object} config The DDProxy config object
487 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
488 * @return {Roo.dd.DDProxy} The DDProxy object
490 initDDProxy : function(group, config, overrides){
491 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
492 return Roo.apply(dd, overrides);
496 * Initializes a {@link Roo.dd.DDTarget} object for this element.
497 * @param {String} group The group the DDTarget object is member of
498 * @param {Object} config The DDTarget config object
499 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
500 * @return {Roo.dd.DDTarget} The DDTarget object
502 initDDTarget : function(group, config, overrides){
503 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
504 return Roo.apply(dd, overrides);
508 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
509 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
510 * @param {Boolean} visible Whether the element is visible
511 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
512 * @return {Roo.Element} this
514 setVisible : function(visible, animate){
516 if(this.visibilityMode == El.DISPLAY){
517 this.setDisplayed(visible);
520 this.dom.style.visibility = visible ? "visible" : "hidden";
523 // closure for composites
525 var visMode = this.visibilityMode;
527 this.setOpacity(.01);
528 this.setVisible(true);
530 this.anim({opacity: { to: (visible?1:0) }},
531 this.preanim(arguments, 1),
532 null, .35, 'easeIn', function(){
534 if(visMode == El.DISPLAY){
535 dom.style.display = "none";
537 dom.style.visibility = "hidden";
539 Roo.get(dom).setOpacity(1);
547 * Returns true if display is not "none"
550 isDisplayed : function() {
551 return this.getStyle("display") != "none";
555 * Toggles the element's visibility or display, depending on visibility mode.
556 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
557 * @return {Roo.Element} this
559 toggle : function(animate){
560 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
565 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
566 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
567 * @return {Roo.Element} this
569 setDisplayed : function(value) {
570 if(typeof value == "boolean"){
571 value = value ? this.originalDisplay : "none";
573 this.setStyle("display", value);
578 * Tries to focus the element. Any exceptions are caught and ignored.
579 * @return {Roo.Element} this
589 * Tries to blur the element. Any exceptions are caught and ignored.
590 * @return {Roo.Element} this
600 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
601 * @param {String/Array} className The CSS class to add, or an array of classes
602 * @return {Roo.Element} this
604 addClass : function(className){
605 if(className instanceof Array){
606 for(var i = 0, len = className.length; i < len; i++) {
607 this.addClass(className[i]);
610 if(className && !this.hasClass(className)){
611 this.dom.className = this.dom.className + " " + className;
618 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
619 * @param {String/Array} className The CSS class to add, or an array of classes
620 * @return {Roo.Element} this
622 radioClass : function(className){
623 var siblings = this.dom.parentNode.childNodes;
624 for(var i = 0; i < siblings.length; i++) {
627 Roo.get(s).removeClass(className);
630 this.addClass(className);
635 * Removes one or more CSS classes from the element.
636 * @param {String/Array} className The CSS class to remove, or an array of classes
637 * @return {Roo.Element} this
639 removeClass : function(className){
640 if(!className || !this.dom.className){
643 if(className instanceof Array){
644 for(var i = 0, len = className.length; i < len; i++) {
645 this.removeClass(className[i]);
648 if(this.hasClass(className)){
649 var re = this.classReCache[className];
651 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
652 this.classReCache[className] = re;
655 this.dom.className.replace(re, " ");
665 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
666 * @param {String} className The CSS class to toggle
667 * @return {Roo.Element} this
669 toggleClass : function(className){
670 if(this.hasClass(className)){
671 this.removeClass(className);
673 this.addClass(className);
679 * Checks if the specified CSS class exists on this element's DOM node.
680 * @param {String} className The CSS class to check for
681 * @return {Boolean} True if the class exists, else false
683 hasClass : function(className){
684 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
688 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
689 * @param {String} oldClassName The CSS class to replace
690 * @param {String} newClassName The replacement CSS class
691 * @return {Roo.Element} this
693 replaceClass : function(oldClassName, newClassName){
694 this.removeClass(oldClassName);
695 this.addClass(newClassName);
700 * Returns an object with properties matching the styles requested.
701 * For example, el.getStyles('color', 'font-size', 'width') might return
702 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
703 * @param {String} style1 A style name
704 * @param {String} style2 A style name
705 * @param {String} etc.
706 * @return {Object} The style object
708 getStyles : function(){
709 var a = arguments, len = a.length, r = {};
710 for(var i = 0; i < len; i++){
711 r[a[i]] = this.getStyle(a[i]);
717 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
718 * @param {String} property The style property whose value is returned.
719 * @return {String} The current value of the style property for this element.
721 getStyle : function(){
722 return view && view.getComputedStyle ?
724 var el = this.dom, v, cs, camel;
728 if(el.style && (v = el.style[prop])){
731 if(cs = view.getComputedStyle(el, "")){
732 if(!(camel = propCache[prop])){
733 camel = propCache[prop] = prop.replace(camelRe, camelFn);
740 var el = this.dom, v, cs, camel;
741 if(prop == 'opacity'){
742 if(typeof el.style.filter == 'string'){
743 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
745 var fv = parseFloat(m[1]);
747 return fv ? fv / 100 : 0;
752 }else if(prop == 'float'){
755 if(!(camel = propCache[prop])){
756 camel = propCache[prop] = prop.replace(camelRe, camelFn);
758 if(v = el.style[camel]){
761 if(cs = el.currentStyle){
769 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
770 * @param {String/Object} property The style property to be set, or an object of multiple styles.
771 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
772 * @return {Roo.Element} this
774 setStyle : function(prop, value){
775 if(typeof prop == "string"){
777 if (prop == 'float') {
778 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
783 if(!(camel = propCache[prop])){
784 camel = propCache[prop] = prop.replace(camelRe, camelFn);
787 if(camel == 'opacity') {
788 this.setOpacity(value);
790 this.dom.style[camel] = value;
793 for(var style in prop){
794 if(typeof prop[style] != "function"){
795 this.setStyle(style, prop[style]);
803 * More flexible version of {@link #setStyle} for setting style properties.
804 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
805 * a function which returns such a specification.
806 * @return {Roo.Element} this
808 applyStyles : function(style){
809 Roo.DomHelper.applyStyles(this.dom, style);
814 * 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).
815 * @return {Number} The X position of the element
818 return D.getX(this.dom);
822 * 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).
823 * @return {Number} The Y position of the element
826 return D.getY(this.dom);
830 * 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).
831 * @return {Array} The XY position of the element
834 return D.getXY(this.dom);
838 * 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).
839 * @param {Number} The X position of the element
840 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
841 * @return {Roo.Element} this
843 setX : function(x, animate){
847 this.setXY([x, this.getY()], this.preanim(arguments, 1));
853 * 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).
854 * @param {Number} The Y position of the element
855 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
856 * @return {Roo.Element} this
858 setY : function(y, animate){
862 this.setXY([this.getX(), y], this.preanim(arguments, 1));
868 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
869 * @param {String} left The left CSS property value
870 * @return {Roo.Element} this
872 setLeft : function(left){
873 this.setStyle("left", this.addUnits(left));
878 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
879 * @param {String} top The top CSS property value
880 * @return {Roo.Element} this
882 setTop : function(top){
883 this.setStyle("top", this.addUnits(top));
888 * Sets the element's CSS right style.
889 * @param {String} right The right CSS property value
890 * @return {Roo.Element} this
892 setRight : function(right){
893 this.setStyle("right", this.addUnits(right));
898 * Sets the element's CSS bottom style.
899 * @param {String} bottom The bottom CSS property value
900 * @return {Roo.Element} this
902 setBottom : function(bottom){
903 this.setStyle("bottom", this.addUnits(bottom));
908 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
909 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
910 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
911 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
912 * @return {Roo.Element} this
914 setXY : function(pos, animate){
916 D.setXY(this.dom, pos);
918 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
924 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
925 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
926 * @param {Number} x X value for new position (coordinates are page-based)
927 * @param {Number} y Y value for new position (coordinates are page-based)
928 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
929 * @return {Roo.Element} this
931 setLocation : function(x, y, animate){
932 this.setXY([x, y], this.preanim(arguments, 2));
937 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
938 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
939 * @param {Number} x X value for new position (coordinates are page-based)
940 * @param {Number} y Y value for new position (coordinates are page-based)
941 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
942 * @return {Roo.Element} this
944 moveTo : function(x, y, animate){
945 this.setXY([x, y], this.preanim(arguments, 2));
950 * Returns the region of the given element.
951 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
952 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
954 getRegion : function(){
955 return D.getRegion(this.dom);
959 * Returns the offset height of the element
960 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
961 * @return {Number} The element's height
963 getHeight : function(contentHeight){
964 var h = this.dom.offsetHeight || 0;
965 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
969 * Returns the offset width of the element
970 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
971 * @return {Number} The element's width
973 getWidth : function(contentWidth){
974 var w = this.dom.offsetWidth || 0;
975 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
979 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
980 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
981 * if a height has not been set using CSS.
984 getComputedHeight : function(){
985 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
987 h = parseInt(this.getStyle('height'), 10) || 0;
988 if(!this.isBorderBox()){
989 h += this.getFrameWidth('tb');
996 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
997 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
998 * if a width has not been set using CSS.
1001 getComputedWidth : function(){
1002 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1004 w = parseInt(this.getStyle('width'), 10) || 0;
1005 if(!this.isBorderBox()){
1006 w += this.getFrameWidth('lr');
1013 * Returns the size of the element.
1014 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1015 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1017 getSize : function(contentSize){
1018 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1022 * Returns the width and height of the viewport.
1023 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1025 getViewSize : function(){
1026 var d = this.dom, doc = document, aw = 0, ah = 0;
1027 if(d == doc || d == doc.body){
1028 return {width : D.getViewWidth(), height: D.getViewHeight()};
1031 width : d.clientWidth,
1032 height: d.clientHeight
1038 * Returns the value of the "value" attribute
1039 * @param {Boolean} asNumber true to parse the value as a number
1040 * @return {String/Number}
1042 getValue : function(asNumber){
1043 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1047 adjustWidth : function(width){
1048 if(typeof width == "number"){
1049 if(this.autoBoxAdjust && !this.isBorderBox()){
1050 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1060 adjustHeight : function(height){
1061 if(typeof height == "number"){
1062 if(this.autoBoxAdjust && !this.isBorderBox()){
1063 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1073 * Set the width of the element
1074 * @param {Number} width The new width
1075 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1076 * @return {Roo.Element} this
1078 setWidth : function(width, animate){
1079 width = this.adjustWidth(width);
1081 this.dom.style.width = this.addUnits(width);
1083 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1089 * Set the height of the element
1090 * @param {Number} height The new height
1091 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1092 * @return {Roo.Element} this
1094 setHeight : function(height, animate){
1095 height = this.adjustHeight(height);
1097 this.dom.style.height = this.addUnits(height);
1099 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1105 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1106 * @param {Number} width The new width
1107 * @param {Number} height The new height
1108 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1109 * @return {Roo.Element} this
1111 setSize : function(width, height, animate){
1112 if(typeof width == "object"){ // in case of object from getSize()
1113 height = width.height; width = width.width;
1115 width = this.adjustWidth(width); height = this.adjustHeight(height);
1117 this.dom.style.width = this.addUnits(width);
1118 this.dom.style.height = this.addUnits(height);
1120 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1126 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1127 * @param {Number} x X value for new position (coordinates are page-based)
1128 * @param {Number} y Y value for new position (coordinates are page-based)
1129 * @param {Number} width The new width
1130 * @param {Number} height The new height
1131 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1132 * @return {Roo.Element} this
1134 setBounds : function(x, y, width, height, animate){
1136 this.setSize(width, height);
1137 this.setLocation(x, y);
1139 width = this.adjustWidth(width); height = this.adjustHeight(height);
1140 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1141 this.preanim(arguments, 4), 'motion');
1147 * 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.
1148 * @param {Roo.lib.Region} region The region to fill
1149 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1150 * @return {Roo.Element} this
1152 setRegion : function(region, animate){
1153 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1158 * Appends an event handler
1160 * @param {String} eventName The type of event to append
1161 * @param {Function} fn The method the event invokes
1162 * @param {Object} scope (optional) The scope (this object) of the fn
1163 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1165 addListener : function(eventName, fn, scope, options){
1167 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1172 * Removes an event handler from this element
1173 * @param {String} eventName the type of event to remove
1174 * @param {Function} fn the method the event invokes
1175 * @return {Roo.Element} this
1177 removeListener : function(eventName, fn){
1178 Roo.EventManager.removeListener(this.dom, eventName, fn);
1183 * Removes all previous added listeners from this element
1184 * @return {Roo.Element} this
1186 removeAllListeners : function(){
1187 E.purgeElement(this.dom);
1191 relayEvent : function(eventName, observable){
1192 this.on(eventName, function(e){
1193 observable.fireEvent(eventName, e);
1198 * Set the opacity of the element
1199 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1200 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1201 * @return {Roo.Element} this
1203 setOpacity : function(opacity, animate){
1205 var s = this.dom.style;
1208 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1209 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1211 s.opacity = opacity;
1214 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1220 * Gets the left X coordinate
1221 * @param {Boolean} local True to get the local css position instead of page coordinate
1224 getLeft : function(local){
1228 return parseInt(this.getStyle("left"), 10) || 0;
1233 * Gets the right X coordinate of the element (element X position + element width)
1234 * @param {Boolean} local True to get the local css position instead of page coordinate
1237 getRight : function(local){
1239 return this.getX() + this.getWidth();
1241 return (this.getLeft(true) + this.getWidth()) || 0;
1246 * Gets the top Y coordinate
1247 * @param {Boolean} local True to get the local css position instead of page coordinate
1250 getTop : function(local) {
1254 return parseInt(this.getStyle("top"), 10) || 0;
1259 * Gets the bottom Y coordinate of the element (element Y position + element height)
1260 * @param {Boolean} local True to get the local css position instead of page coordinate
1263 getBottom : function(local){
1265 return this.getY() + this.getHeight();
1267 return (this.getTop(true) + this.getHeight()) || 0;
1272 * Initializes positioning on this element. If a desired position is not passed, it will make the
1273 * the element positioned relative IF it is not already positioned.
1274 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1275 * @param {Number} zIndex (optional) The zIndex to apply
1276 * @param {Number} x (optional) Set the page X position
1277 * @param {Number} y (optional) Set the page Y position
1279 position : function(pos, zIndex, x, y){
1281 if(this.getStyle('position') == 'static'){
1282 this.setStyle('position', 'relative');
1285 this.setStyle("position", pos);
1288 this.setStyle("z-index", zIndex);
1290 if(x !== undefined && y !== undefined){
1292 }else if(x !== undefined){
1294 }else if(y !== undefined){
1300 * Clear positioning back to the default when the document was loaded
1301 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1302 * @return {Roo.Element} this
1304 clearPositioning : function(value){
1312 "position" : "static"
1318 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1319 * snapshot before performing an update and then restoring the element.
1322 getPositioning : function(){
1323 var l = this.getStyle("left");
1324 var t = this.getStyle("top");
1326 "position" : this.getStyle("position"),
1328 "right" : l ? "" : this.getStyle("right"),
1330 "bottom" : t ? "" : this.getStyle("bottom"),
1331 "z-index" : this.getStyle("z-index")
1336 * Gets the width of the border(s) for the specified side(s)
1337 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1338 * passing lr would get the border (l)eft width + the border (r)ight width.
1339 * @return {Number} The width of the sides passed added together
1341 getBorderWidth : function(side){
1342 return this.addStyles(side, El.borders);
1346 * Gets the width of the padding(s) for the specified side(s)
1347 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1348 * passing lr would get the padding (l)eft + the padding (r)ight.
1349 * @return {Number} The padding of the sides passed added together
1351 getPadding : function(side){
1352 return this.addStyles(side, El.paddings);
1356 * Set positioning with an object returned by getPositioning().
1357 * @param {Object} posCfg
1358 * @return {Roo.Element} this
1360 setPositioning : function(pc){
1361 this.applyStyles(pc);
1362 if(pc.right == "auto"){
1363 this.dom.style.right = "";
1365 if(pc.bottom == "auto"){
1366 this.dom.style.bottom = "";
1372 fixDisplay : function(){
1373 if(this.getStyle("display") == "none"){
1374 this.setStyle("visibility", "hidden");
1375 this.setStyle("display", this.originalDisplay); // first try reverting to default
1376 if(this.getStyle("display") == "none"){ // if that fails, default to block
1377 this.setStyle("display", "block");
1383 * Quick set left and top adding default units
1384 * @param {String} left The left CSS property value
1385 * @param {String} top The top CSS property value
1386 * @return {Roo.Element} this
1388 setLeftTop : function(left, top){
1389 this.dom.style.left = this.addUnits(left);
1390 this.dom.style.top = this.addUnits(top);
1395 * Move this element relative to its current position.
1396 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1397 * @param {Number} distance How far to move the element in pixels
1398 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1399 * @return {Roo.Element} this
1401 move : function(direction, distance, animate){
1402 var xy = this.getXY();
1403 direction = direction.toLowerCase();
1407 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1411 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1416 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1421 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1428 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1429 * @return {Roo.Element} this
1432 if(!this.isClipped){
1433 this.isClipped = true;
1434 this.originalClip = {
1435 "o": this.getStyle("overflow"),
1436 "x": this.getStyle("overflow-x"),
1437 "y": this.getStyle("overflow-y")
1439 this.setStyle("overflow", "hidden");
1440 this.setStyle("overflow-x", "hidden");
1441 this.setStyle("overflow-y", "hidden");
1447 * Return clipping (overflow) to original clipping before clip() was called
1448 * @return {Roo.Element} this
1450 unclip : function(){
1452 this.isClipped = false;
1453 var o = this.originalClip;
1454 if(o.o){this.setStyle("overflow", o.o);}
1455 if(o.x){this.setStyle("overflow-x", o.x);}
1456 if(o.y){this.setStyle("overflow-y", o.y);}
1463 * Gets the x,y coordinates specified by the anchor position on the element.
1464 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1465 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1466 * {width: (target width), height: (target height)} (defaults to the element's current size)
1467 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1468 * @return {Array} [x, y] An array containing the element's x and y coordinates
1470 getAnchorXY : function(anchor, local, s){
1471 //Passing a different size is useful for pre-calculating anchors,
1472 //especially for anchored animations that change the el size.
1474 var w, h, vp = false;
1477 if(d == document.body || d == document){
1479 w = D.getViewWidth(); h = D.getViewHeight();
1481 w = this.getWidth(); h = this.getHeight();
1484 w = s.width; h = s.height;
1486 var x = 0, y = 0, r = Math.round;
1487 switch((anchor || "tl").toLowerCase()){
1529 var sc = this.getScroll();
1530 return [x + sc.left, y + sc.top];
1532 //Add the element's offset xy
1533 var o = this.getXY();
1534 return [x+o[0], y+o[1]];
1538 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1539 * supported position values.
1540 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1541 * @param {String} position The position to align to.
1542 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1543 * @return {Array} [x, y]
1545 getAlignToXY : function(el, p, o){
1549 throw "Element.alignTo with an element that doesn't exist";
1551 var c = false; //constrain to viewport
1552 var p1 = "", p2 = "";
1559 }else if(p.indexOf("-") == -1){
1562 p = p.toLowerCase();
1563 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1565 throw "Element.alignTo with an invalid alignment " + p;
1567 p1 = m[1]; p2 = m[2]; c = !!m[3];
1569 //Subtract the aligned el's internal xy from the target's offset xy
1570 //plus custom offset to get the aligned el's new offset xy
1571 var a1 = this.getAnchorXY(p1, true);
1572 var a2 = el.getAnchorXY(p2, false);
1573 var x = a2[0] - a1[0] + o[0];
1574 var y = a2[1] - a1[1] + o[1];
1576 //constrain the aligned el to viewport if necessary
1577 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1578 // 5px of margin for ie
1579 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1581 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1582 //perpendicular to the vp border, allow the aligned el to slide on that border,
1583 //otherwise swap the aligned el to the opposite border of the target.
1584 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1585 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1586 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1587 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1590 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1591 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1593 if((x+w) > dw + scrollX){
1594 x = swapX ? r.left-w : dw+scrollX-w;
1597 x = swapX ? r.right : scrollX;
1599 if((y+h) > dh + scrollY){
1600 y = swapY ? r.top-h : dh+scrollY-h;
1603 y = swapY ? r.bottom : scrollY;
1610 getConstrainToXY : function(){
1611 var os = {top:0, left:0, bottom:0, right: 0};
1613 return function(el, local, offsets, proposedXY){
1615 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1617 var vw, vh, vx = 0, vy = 0;
1618 if(el.dom == document.body || el.dom == document){
1619 vw = Roo.lib.Dom.getViewWidth();
1620 vh = Roo.lib.Dom.getViewHeight();
1622 vw = el.dom.clientWidth;
1623 vh = el.dom.clientHeight;
1625 var vxy = el.getXY();
1631 var s = el.getScroll();
1633 vx += offsets.left + s.left;
1634 vy += offsets.top + s.top;
1636 vw -= offsets.right;
1637 vh -= offsets.bottom;
1642 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1643 var x = xy[0], y = xy[1];
1644 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1646 // only move it if it needs it
1649 // first validate right/bottom
1658 // then make sure top/left isn't negative
1667 return moved ? [x, y] : false;
1672 adjustForConstraints : function(xy, parent, offsets){
1673 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1677 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1678 * document it aligns it to the viewport.
1679 * The position parameter is optional, and can be specified in any one of the following formats:
1681 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1682 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1683 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1684 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1685 * <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
1686 * element's anchor point, and the second value is used as the target's anchor point.</li>
1688 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1689 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1690 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1691 * that specified in order to enforce the viewport constraints.
1692 * Following are all of the supported anchor positions:
1695 ----- -----------------------------
1696 tl The top left corner (default)
1697 t The center of the top edge
1698 tr The top right corner
1699 l The center of the left edge
1700 c In the center of the element
1701 r The center of the right edge
1702 bl The bottom left corner
1703 b The center of the bottom edge
1704 br The bottom right corner
1708 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1709 el.alignTo("other-el");
1711 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1712 el.alignTo("other-el", "tr?");
1714 // align the bottom right corner of el with the center left edge of other-el
1715 el.alignTo("other-el", "br-l?");
1717 // align the center of el with the bottom left corner of other-el and
1718 // adjust the x position by -6 pixels (and the y position by 0)
1719 el.alignTo("other-el", "c-bl", [-6, 0]);
1721 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1722 * @param {String} position The position to align to.
1723 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1724 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1725 * @return {Roo.Element} this
1727 alignTo : function(element, position, offsets, animate){
1728 var xy = this.getAlignToXY(element, position, offsets);
1729 this.setXY(xy, this.preanim(arguments, 3));
1734 * Anchors an element to another element and realigns it when the window is resized.
1735 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1736 * @param {String} position The position to align to.
1737 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1738 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1739 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1740 * is a number, it is used as the buffer delay (defaults to 50ms).
1741 * @param {Function} callback The function to call after the animation finishes
1742 * @return {Roo.Element} this
1744 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1745 var action = function(){
1746 this.alignTo(el, alignment, offsets, animate);
1747 Roo.callback(callback, this);
1749 Roo.EventManager.onWindowResize(action, this);
1750 var tm = typeof monitorScroll;
1751 if(tm != 'undefined'){
1752 Roo.EventManager.on(window, 'scroll', action, this,
1753 {buffer: tm == 'number' ? monitorScroll : 50});
1755 action.call(this); // align immediately
1759 * Clears any opacity settings from this element. Required in some cases for IE.
1760 * @return {Roo.Element} this
1762 clearOpacity : function(){
1763 if (window.ActiveXObject) {
1764 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1765 this.dom.style.filter = "";
1768 this.dom.style.opacity = "";
1769 this.dom.style["-moz-opacity"] = "";
1770 this.dom.style["-khtml-opacity"] = "";
1776 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1777 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1778 * @return {Roo.Element} this
1780 hide : function(animate){
1781 this.setVisible(false, this.preanim(arguments, 0));
1786 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1787 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1788 * @return {Roo.Element} this
1790 show : function(animate){
1791 this.setVisible(true, this.preanim(arguments, 0));
1796 * @private Test if size has a unit, otherwise appends the default
1798 addUnits : function(size){
1799 return Roo.Element.addUnits(size, this.defaultUnit);
1803 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1804 * @return {Roo.Element} this
1806 beginMeasure : function(){
1808 if(el.offsetWidth || el.offsetHeight){
1809 return this; // offsets work already
1812 var p = this.dom, b = document.body; // start with this element
1813 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1814 var pe = Roo.get(p);
1815 if(pe.getStyle('display') == 'none'){
1816 changed.push({el: p, visibility: pe.getStyle("visibility")});
1817 p.style.visibility = "hidden";
1818 p.style.display = "block";
1822 this._measureChanged = changed;
1828 * Restores displays to before beginMeasure was called
1829 * @return {Roo.Element} this
1831 endMeasure : function(){
1832 var changed = this._measureChanged;
1834 for(var i = 0, len = changed.length; i < len; i++) {
1836 r.el.style.visibility = r.visibility;
1837 r.el.style.display = "none";
1839 this._measureChanged = null;
1845 * Update the innerHTML of this element, optionally searching for and processing scripts
1846 * @param {String} html The new HTML
1847 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1848 * @param {Function} callback For async script loading you can be noticed when the update completes
1849 * @return {Roo.Element} this
1851 update : function(html, loadScripts, callback){
1852 if(typeof html == "undefined"){
1855 if(loadScripts !== true){
1856 this.dom.innerHTML = html;
1857 if(typeof callback == "function"){
1865 html += '<span id="' + id + '"></span>';
1867 E.onAvailable(id, function(){
1868 var hd = document.getElementsByTagName("head")[0];
1869 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1870 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1871 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1874 while(match = re.exec(html)){
1875 var attrs = match[1];
1876 var srcMatch = attrs ? attrs.match(srcRe) : false;
1877 if(srcMatch && srcMatch[2]){
1878 var s = document.createElement("script");
1879 s.src = srcMatch[2];
1880 var typeMatch = attrs.match(typeRe);
1881 if(typeMatch && typeMatch[2]){
1882 s.type = typeMatch[2];
1885 }else if(match[2] && match[2].length > 0){
1886 if(window.execScript) {
1887 window.execScript(match[2]);
1895 window.eval(match[2]);
1899 var el = document.getElementById(id);
1900 if(el){el.parentNode.removeChild(el);}
1901 if(typeof callback == "function"){
1905 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1910 * Direct access to the UpdateManager update() method (takes the same parameters).
1911 * @param {String/Function} url The url for this request or a function to call to get the url
1912 * @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}
1913 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1914 * @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.
1915 * @return {Roo.Element} this
1918 var um = this.getUpdateManager();
1919 um.update.apply(um, arguments);
1924 * Gets this element's UpdateManager
1925 * @return {Roo.UpdateManager} The UpdateManager
1927 getUpdateManager : function(){
1928 if(!this.updateManager){
1929 this.updateManager = new Roo.UpdateManager(this);
1931 return this.updateManager;
1935 * Disables text selection for this element (normalized across browsers)
1936 * @return {Roo.Element} this
1938 unselectable : function(){
1939 this.dom.unselectable = "on";
1940 this.swallowEvent("selectstart", true);
1941 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1942 this.addClass("x-unselectable");
1947 * Calculates the x, y to center this element on the screen
1948 * @return {Array} The x, y values [x, y]
1950 getCenterXY : function(){
1951 return this.getAlignToXY(document, 'c-c');
1955 * Centers the Element in either the viewport, or another Element.
1956 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1958 center : function(centerIn){
1959 this.alignTo(centerIn || document, 'c-c');
1964 * Tests various css rules/browsers to determine if this element uses a border box
1967 isBorderBox : function(){
1968 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1972 * Return a box {x, y, width, height} that can be used to set another elements
1973 * size/location to match this element.
1974 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1975 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1976 * @return {Object} box An object in the format {x, y, width, height}
1978 getBox : function(contentBox, local){
1983 var left = parseInt(this.getStyle("left"), 10) || 0;
1984 var top = parseInt(this.getStyle("top"), 10) || 0;
1987 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
1989 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
1991 var l = this.getBorderWidth("l")+this.getPadding("l");
1992 var r = this.getBorderWidth("r")+this.getPadding("r");
1993 var t = this.getBorderWidth("t")+this.getPadding("t");
1994 var b = this.getBorderWidth("b")+this.getPadding("b");
1995 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)};
1997 bx.right = bx.x + bx.width;
1998 bx.bottom = bx.y + bx.height;
2003 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2004 for more information about the sides.
2005 * @param {String} sides
2008 getFrameWidth : function(sides, onlyContentBox){
2009 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2013 * 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.
2014 * @param {Object} box The box to fill {x, y, width, height}
2015 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2016 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2017 * @return {Roo.Element} this
2019 setBox : function(box, adjust, animate){
2020 var w = box.width, h = box.height;
2021 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2022 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2023 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2025 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2030 * Forces the browser to repaint this element
2031 * @return {Roo.Element} this
2033 repaint : function(){
2035 this.addClass("x-repaint");
2036 setTimeout(function(){
2037 Roo.get(dom).removeClass("x-repaint");
2043 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2044 * then it returns the calculated width of the sides (see getPadding)
2045 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2046 * @return {Object/Number}
2048 getMargins : function(side){
2051 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2052 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2053 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2054 right: parseInt(this.getStyle("margin-right"), 10) || 0
2057 return this.addStyles(side, El.margins);
2062 addStyles : function(sides, styles){
2064 for(var i = 0, len = sides.length; i < len; i++){
2065 v = this.getStyle(styles[sides.charAt(i)]);
2067 w = parseInt(v, 10);
2075 * Creates a proxy element of this element
2076 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2077 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2078 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2079 * @return {Roo.Element} The new proxy element
2081 createProxy : function(config, renderTo, matchBox){
2083 renderTo = Roo.getDom(renderTo);
2085 renderTo = document.body;
2087 config = typeof config == "object" ?
2088 config : {tag : "div", cls: config};
2089 var proxy = Roo.DomHelper.append(renderTo, config, true);
2091 proxy.setBox(this.getBox());
2097 * Puts a mask over this element to disable user interaction. Requires core.css.
2098 * This method can only be applied to elements which accept child nodes.
2099 * @param {String} msg (optional) A message to display in the mask
2100 * @param {String} msgCls (optional) A css class to apply to the msg element
2101 * @return {Element} The mask element
2103 mask : function(msg, msgCls)
2105 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2106 this.setStyle("position", "relative");
2109 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2111 this.addClass("x-masked");
2112 this._mask.setDisplayed(true);
2117 while (dom && dom.style) {
2118 if (!isNaN(parseInt(dom.style.zIndex))) {
2119 z = Math.max(z, parseInt(dom.style.zIndex));
2121 dom = dom.parentNode;
2123 // if we are masking the body - then it hides everything..
2124 if (this.dom == document.body) {
2126 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2127 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2130 if(typeof msg == 'string'){
2132 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2134 var mm = this._maskMsg;
2135 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2136 if (mm.dom.firstChild) { // weird IE issue?
2137 mm.dom.firstChild.innerHTML = msg;
2139 mm.setDisplayed(true);
2141 mm.setStyle('z-index', z + 102);
2143 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2144 this._mask.setHeight(this.getHeight());
2146 this._mask.setStyle('z-index', z + 100);
2152 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2153 * it is cached for reuse.
2155 unmask : function(removeEl){
2157 if(removeEl === true){
2158 this._mask.remove();
2161 this._maskMsg.remove();
2162 delete this._maskMsg;
2165 this._mask.setDisplayed(false);
2167 this._maskMsg.setDisplayed(false);
2171 this.removeClass("x-masked");
2175 * Returns true if this element is masked
2178 isMasked : function(){
2179 return this._mask && this._mask.isVisible();
2183 * Creates an iframe shim for this element to keep selects and other windowed objects from
2185 * @return {Roo.Element} The new shim element
2187 createShim : function(){
2188 var el = document.createElement('iframe');
2189 el.frameBorder = 'no';
2190 el.className = 'roo-shim';
2191 if(Roo.isIE && Roo.isSecure){
2192 el.src = Roo.SSL_SECURE_URL;
2194 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2195 shim.autoBoxAdjust = false;
2200 * Removes this element from the DOM and deletes it from the cache
2202 remove : function(){
2203 if(this.dom.parentNode){
2204 this.dom.parentNode.removeChild(this.dom);
2206 delete El.cache[this.dom.id];
2210 * Sets up event handlers to add and remove a css class when the mouse is over this element
2211 * @param {String} className
2212 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2213 * mouseout events for children elements
2214 * @return {Roo.Element} this
2216 addClassOnOver : function(className, preventFlicker){
2217 this.on("mouseover", function(){
2218 Roo.fly(this, '_internal').addClass(className);
2220 var removeFn = function(e){
2221 if(preventFlicker !== true || !e.within(this, true)){
2222 Roo.fly(this, '_internal').removeClass(className);
2225 this.on("mouseout", removeFn, this.dom);
2230 * Sets up event handlers to add and remove a css class when this element has the focus
2231 * @param {String} className
2232 * @return {Roo.Element} this
2234 addClassOnFocus : function(className){
2235 this.on("focus", function(){
2236 Roo.fly(this, '_internal').addClass(className);
2238 this.on("blur", function(){
2239 Roo.fly(this, '_internal').removeClass(className);
2244 * 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)
2245 * @param {String} className
2246 * @return {Roo.Element} this
2248 addClassOnClick : function(className){
2250 this.on("mousedown", function(){
2251 Roo.fly(dom, '_internal').addClass(className);
2252 var d = Roo.get(document);
2253 var fn = function(){
2254 Roo.fly(dom, '_internal').removeClass(className);
2255 d.removeListener("mouseup", fn);
2257 d.on("mouseup", fn);
2263 * Stops the specified event from bubbling and optionally prevents the default action
2264 * @param {String} eventName
2265 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2266 * @return {Roo.Element} this
2268 swallowEvent : function(eventName, preventDefault){
2269 var fn = function(e){
2270 e.stopPropagation();
2275 if(eventName instanceof Array){
2276 for(var i = 0, len = eventName.length; i < len; i++){
2277 this.on(eventName[i], fn);
2281 this.on(eventName, fn);
2288 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2291 * Sizes this element to its parent element's dimensions performing
2292 * neccessary box adjustments.
2293 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2294 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2295 * @return {Roo.Element} this
2297 fitToParent : function(monitorResize, targetParent) {
2298 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2299 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2300 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2303 var p = Roo.get(targetParent || this.dom.parentNode);
2304 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2305 if (monitorResize === true) {
2306 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2307 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2313 * Gets the next sibling, skipping text nodes
2314 * @return {HTMLElement} The next sibling or null
2316 getNextSibling : function(){
2317 var n = this.dom.nextSibling;
2318 while(n && n.nodeType != 1){
2325 * Gets the previous sibling, skipping text nodes
2326 * @return {HTMLElement} The previous sibling or null
2328 getPrevSibling : function(){
2329 var n = this.dom.previousSibling;
2330 while(n && n.nodeType != 1){
2331 n = n.previousSibling;
2338 * Appends the passed element(s) to this element
2339 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2340 * @return {Roo.Element} this
2342 appendChild: function(el){
2349 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2350 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2351 * automatically generated with the specified attributes.
2352 * @param {HTMLElement} insertBefore (optional) a child element of this element
2353 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2354 * @return {Roo.Element} The new child element
2356 createChild: function(config, insertBefore, returnDom){
2357 config = config || {tag:'div'};
2359 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2361 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2365 * Appends this element to the passed element
2366 * @param {String/HTMLElement/Element} el The new parent element
2367 * @return {Roo.Element} this
2369 appendTo: function(el){
2370 el = Roo.getDom(el);
2371 el.appendChild(this.dom);
2376 * Inserts this element before the passed element in the DOM
2377 * @param {String/HTMLElement/Element} el The element to insert before
2378 * @return {Roo.Element} this
2380 insertBefore: function(el){
2381 el = Roo.getDom(el);
2382 el.parentNode.insertBefore(this.dom, el);
2387 * Inserts this element after the passed element in the DOM
2388 * @param {String/HTMLElement/Element} el The element to insert after
2389 * @return {Roo.Element} this
2391 insertAfter: function(el){
2392 el = Roo.getDom(el);
2393 el.parentNode.insertBefore(this.dom, el.nextSibling);
2398 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2399 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2400 * @return {Roo.Element} The new child
2402 insertFirst: function(el, returnDom){
2404 if(typeof el == 'object' && !el.nodeType){ // dh config
2405 return this.createChild(el, this.dom.firstChild, returnDom);
2407 el = Roo.getDom(el);
2408 this.dom.insertBefore(el, this.dom.firstChild);
2409 return !returnDom ? Roo.get(el) : el;
2414 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2415 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2416 * @param {String} where (optional) 'before' or 'after' defaults to before
2417 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2418 * @return {Roo.Element} the inserted Element
2420 insertSibling: function(el, where, returnDom){
2421 where = where ? where.toLowerCase() : 'before';
2423 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2425 if(typeof el == 'object' && !el.nodeType){ // dh config
2426 if(where == 'after' && !this.dom.nextSibling){
2427 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2429 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2433 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2434 where == 'before' ? this.dom : this.dom.nextSibling);
2443 * Creates and wraps this element with another element
2444 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2445 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2446 * @return {HTMLElement/Element} The newly created wrapper element
2448 wrap: function(config, returnDom){
2450 config = {tag: "div"};
2452 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2453 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2458 * Replaces the passed element with this element
2459 * @param {String/HTMLElement/Element} el The element to replace
2460 * @return {Roo.Element} this
2462 replace: function(el){
2464 this.insertBefore(el);
2470 * Inserts an html fragment into this element
2471 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2472 * @param {String} html The HTML fragment
2473 * @param {Boolean} returnEl True to return an Roo.Element
2474 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2476 insertHtml : function(where, html, returnEl){
2477 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2478 return returnEl ? Roo.get(el) : el;
2482 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2483 * @param {Object} o The object with the attributes
2484 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2485 * @return {Roo.Element} this
2487 set : function(o, useSet){
2489 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2491 if(attr == "style" || typeof o[attr] == "function") { continue; }
2493 el.className = o["cls"];
2496 el.setAttribute(attr, o[attr]);
2503 Roo.DomHelper.applyStyles(el, o.style);
2509 * Convenience method for constructing a KeyMap
2510 * @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:
2511 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2512 * @param {Function} fn The function to call
2513 * @param {Object} scope (optional) The scope of the function
2514 * @return {Roo.KeyMap} The KeyMap created
2516 addKeyListener : function(key, fn, scope){
2518 if(typeof key != "object" || key instanceof Array){
2534 return new Roo.KeyMap(this, config);
2538 * Creates a KeyMap for this element
2539 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2540 * @return {Roo.KeyMap} The KeyMap created
2542 addKeyMap : function(config){
2543 return new Roo.KeyMap(this, config);
2547 * Returns true if this element is scrollable.
2550 isScrollable : function(){
2552 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2556 * 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().
2557 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2558 * @param {Number} value The new scroll value
2559 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2560 * @return {Element} this
2563 scrollTo : function(side, value, animate){
2564 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2566 this.dom[prop] = value;
2568 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2569 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2575 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2576 * within this element's scrollable range.
2577 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2578 * @param {Number} distance How far to scroll the element in pixels
2579 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2580 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2581 * was scrolled as far as it could go.
2583 scroll : function(direction, distance, animate){
2584 if(!this.isScrollable()){
2588 var l = el.scrollLeft, t = el.scrollTop;
2589 var w = el.scrollWidth, h = el.scrollHeight;
2590 var cw = el.clientWidth, ch = el.clientHeight;
2591 direction = direction.toLowerCase();
2592 var scrolled = false;
2593 var a = this.preanim(arguments, 2);
2598 var v = Math.min(l + distance, w-cw);
2599 this.scrollTo("left", v, a);
2606 var v = Math.max(l - distance, 0);
2607 this.scrollTo("left", v, a);
2615 var v = Math.max(t - distance, 0);
2616 this.scrollTo("top", v, a);
2624 var v = Math.min(t + distance, h-ch);
2625 this.scrollTo("top", v, a);
2634 * Translates the passed page coordinates into left/top css values for this element
2635 * @param {Number/Array} x The page x or an array containing [x, y]
2636 * @param {Number} y The page y
2637 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2639 translatePoints : function(x, y){
2640 if(typeof x == 'object' || x instanceof Array){
2643 var p = this.getStyle('position');
2644 var o = this.getXY();
2646 var l = parseInt(this.getStyle('left'), 10);
2647 var t = parseInt(this.getStyle('top'), 10);
2650 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2653 t = (p == "relative") ? 0 : this.dom.offsetTop;
2656 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2660 * Returns the current scroll position of the element.
2661 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2663 getScroll : function(){
2664 var d = this.dom, doc = document;
2665 if(d == doc || d == doc.body){
2666 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2667 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2668 return {left: l, top: t};
2670 return {left: d.scrollLeft, top: d.scrollTop};
2675 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2676 * are convert to standard 6 digit hex color.
2677 * @param {String} attr The css attribute
2678 * @param {String} defaultValue The default value to use when a valid color isn't found
2679 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2682 getColor : function(attr, defaultValue, prefix){
2683 var v = this.getStyle(attr);
2684 if(!v || v == "transparent" || v == "inherit") {
2685 return defaultValue;
2687 var color = typeof prefix == "undefined" ? "#" : prefix;
2688 if(v.substr(0, 4) == "rgb("){
2689 var rvs = v.slice(4, v.length -1).split(",");
2690 for(var i = 0; i < 3; i++){
2691 var h = parseInt(rvs[i]).toString(16);
2698 if(v.substr(0, 1) == "#"){
2700 for(var i = 1; i < 4; i++){
2701 var c = v.charAt(i);
2704 }else if(v.length == 7){
2705 color += v.substr(1);
2709 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2713 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2714 * gradient background, rounded corners and a 4-way shadow.
2715 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2716 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2717 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2718 * @return {Roo.Element} this
2720 boxWrap : function(cls){
2721 cls = cls || 'x-box';
2722 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2723 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2728 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2729 * @param {String} namespace The namespace in which to look for the attribute
2730 * @param {String} name The attribute name
2731 * @return {String} The attribute value
2733 getAttributeNS : Roo.isIE ? function(ns, name){
2735 var type = typeof d[ns+":"+name];
2736 if(type != 'undefined' && type != 'unknown'){
2737 return d[ns+":"+name];
2740 } : function(ns, name){
2742 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2747 * Sets or Returns the value the dom attribute value
2748 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2749 * @param {String} value (optional) The value to set the attribute to
2750 * @return {String} The attribute value
2752 attr : function(name){
2753 if (arguments.length > 1) {
2754 this.dom.setAttribute(name, arguments[1]);
2755 return arguments[1];
2757 if (typeof(name) == 'object') {
2758 for(var i in name) {
2759 this.attr(i, name[i]);
2765 if (!this.dom.hasAttribute(name)) {
2768 return this.dom.getAttribute(name);
2775 var ep = El.prototype;
2778 * Appends an event handler (Shorthand for addListener)
2779 * @param {String} eventName The type of event to append
2780 * @param {Function} fn The method the event invokes
2781 * @param {Object} scope (optional) The scope (this object) of the fn
2782 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2785 ep.on = ep.addListener;
2787 ep.mon = ep.addListener;
2790 * Removes an event handler from this element (shorthand for removeListener)
2791 * @param {String} eventName the type of event to remove
2792 * @param {Function} fn the method the event invokes
2793 * @return {Roo.Element} this
2796 ep.un = ep.removeListener;
2799 * true to automatically adjust width and height settings for box-model issues (default to true)
2801 ep.autoBoxAdjust = true;
2804 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2807 El.addUnits = function(v, defaultUnit){
2808 if(v === "" || v == "auto"){
2811 if(v === undefined){
2814 if(typeof v == "number" || !El.unitPattern.test(v)){
2815 return v + (defaultUnit || 'px');
2820 // special markup used throughout Roo when box wrapping elements
2821 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>';
2823 * Visibility mode constant - Use visibility to hide element
2829 * Visibility mode constant - Use display to hide element
2835 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2836 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2837 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2849 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2850 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2851 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2852 * @return {Element} The Element object
2855 El.get = function(el){
2857 if(!el){ return null; }
2858 if(typeof el == "string"){ // element id
2859 if(!(elm = document.getElementById(el))){
2862 if(ex = El.cache[el]){
2865 ex = El.cache[el] = new El(elm);
2868 }else if(el.tagName){ // dom element
2872 if(ex = El.cache[id]){
2875 ex = El.cache[id] = new El(el);
2878 }else if(el instanceof El){
2880 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2881 // catch case where it hasn't been appended
2882 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2885 }else if(el.isComposite){
2887 }else if(el instanceof Array){
2888 return El.select(el);
2889 }else if(el == document){
2890 // create a bogus element object representing the document object
2892 var f = function(){};
2893 f.prototype = El.prototype;
2895 docEl.dom = document;
2903 El.uncache = function(el){
2904 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2906 delete El.cache[a[i].id || a[i]];
2912 // Garbage collection - uncache elements/purge listeners on orphaned elements
2913 // so we don't hold a reference and cause the browser to retain them
2914 El.garbageCollect = function(){
2915 if(!Roo.enableGarbageCollector){
2916 clearInterval(El.collectorThread);
2919 for(var eid in El.cache){
2920 var el = El.cache[eid], d = el.dom;
2921 // -------------------------------------------------------
2922 // Determining what is garbage:
2923 // -------------------------------------------------------
2925 // dom node is null, definitely garbage
2926 // -------------------------------------------------------
2928 // no parentNode == direct orphan, definitely garbage
2929 // -------------------------------------------------------
2930 // !d.offsetParent && !document.getElementById(eid)
2931 // display none elements have no offsetParent so we will
2932 // also try to look it up by it's id. However, check
2933 // offsetParent first so we don't do unneeded lookups.
2934 // This enables collection of elements that are not orphans
2935 // directly, but somewhere up the line they have an orphan
2937 // -------------------------------------------------------
2938 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2939 delete El.cache[eid];
2940 if(d && Roo.enableListenerCollection){
2946 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2950 El.Flyweight = function(dom){
2953 El.Flyweight.prototype = El.prototype;
2955 El._flyweights = {};
2957 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2958 * the dom node can be overwritten by other code.
2959 * @param {String/HTMLElement} el The dom node or id
2960 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2961 * prevent conflicts (e.g. internally Roo uses "_internal")
2963 * @return {Element} The shared Element object
2965 El.fly = function(el, named){
2966 named = named || '_global';
2967 el = Roo.getDom(el);
2971 if(!El._flyweights[named]){
2972 El._flyweights[named] = new El.Flyweight();
2974 El._flyweights[named].dom = el;
2975 return El._flyweights[named];
2979 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2980 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2981 * Shorthand of {@link Roo.Element#get}
2982 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2983 * @return {Element} The Element object
2989 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2990 * the dom node can be overwritten by other code.
2991 * Shorthand of {@link Roo.Element#fly}
2992 * @param {String/HTMLElement} el The dom node or id
2993 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2994 * prevent conflicts (e.g. internally Roo uses "_internal")
2996 * @return {Element} The shared Element object
3002 // speedy lookup for elements never to box adjust
3003 var noBoxAdjust = Roo.isStrict ? {
3006 input:1, select:1, textarea:1
3008 if(Roo.isIE || Roo.isGecko){
3009 noBoxAdjust['button'] = 1;
3013 Roo.EventManager.on(window, 'unload', function(){
3015 delete El._flyweights;
3023 Roo.Element.selectorFunction = Roo.DomQuery.select;
3026 Roo.Element.select = function(selector, unique, root){
3028 if(typeof selector == "string"){
3029 els = Roo.Element.selectorFunction(selector, root);
3030 }else if(selector.length !== undefined){
3033 throw "Invalid selector";
3035 if(unique === true){
3036 return new Roo.CompositeElement(els);
3038 return new Roo.CompositeElementLite(els);
3042 * Selects elements based on the passed CSS selector to enable working on them as 1.
3043 * @param {String/Array} selector The CSS selector or an array of elements
3044 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3045 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3046 * @return {CompositeElementLite/CompositeElement}
3050 Roo.select = Roo.Element.select;