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);
194 // Roo.log('D: '+JSON.stringify(D, null, 4));
199 !el.isScrollable() ||
203 D.getViewHeight() - el.dom.clientHeight > 15 ||
204 D.getViewWidth() - el.dom.clientWidth > 15
208 el.dom.nodeName.toLowerCase() != 'body'
213 el = Roo.get(el.dom.parentNode);
215 Roo.log('parentNode');
218 // 'findparent:'+ JSON.stringify(el, null, 4)+
219 // ' | scrollable: '+el.isScrollable()+
220 // ' | D height: '+D.getViewHeight() +
221 // ' | D width: '+D.getViewWidth() +
222 // ' | el height: '+el.dom.clientHeight+
223 // ' | el width: '+el.dom.clientWidth+
231 if(!el.isScrollable()){
239 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
240 * This is a shortcut for findParentNode() that always returns an Roo.Element.
241 * @param {String} selector The simple selector to test
242 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
243 search as a number or element (defaults to 10 || document.body)
244 * @return {Roo.Element} The matching DOM node (or null if no match was found)
246 up : function(simpleSelector, maxDepth){
247 return this.findParentNode(simpleSelector, maxDepth, true);
253 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
254 * @param {String} selector The simple selector to test
255 * @return {Boolean} True if this element matches the selector, else false
257 is : function(simpleSelector){
258 return Roo.DomQuery.is(this.dom, simpleSelector);
262 * Perform animation on this element.
263 * @param {Object} args The YUI animation control args
264 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
265 * @param {Function} onComplete (optional) Function to call when animation completes
266 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
267 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
268 * @return {Roo.Element} this
270 animate : function(args, duration, onComplete, easing, animType){
271 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
276 * @private Internal animation call
278 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
279 animType = animType || 'run';
281 var anim = Roo.lib.Anim[animType](
283 (opt.duration || defaultDur) || .35,
284 (opt.easing || defaultEase) || 'easeOut',
286 Roo.callback(cb, this);
287 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
295 // private legacy anim prep
296 preanim : function(a, i){
297 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
301 * Removes worthless text nodes
302 * @param {Boolean} forceReclean (optional) By default the element
303 * keeps track if it has been cleaned already so
304 * you can call this over and over. However, if you update the element and
305 * need to force a reclean, you can pass true.
307 clean : function(forceReclean){
308 if(this.isCleaned && forceReclean !== true){
312 var d = this.dom, n = d.firstChild, ni = -1;
314 var nx = n.nextSibling;
315 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
322 this.isCleaned = true;
327 calcOffsetsTo : function(el){
330 var restorePos = false;
331 if(el.getStyle('position') == 'static'){
332 el.position('relative');
337 while(op && op != d && op.tagName != 'HTML'){
340 op = op.offsetParent;
343 el.position('static');
349 * Scrolls this element into view within the passed container.
350 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
351 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
352 * @return {Roo.Element} this
354 scrollIntoView : function(container, hscroll){
355 var c = Roo.getDom(container) || document.body;
358 var o = this.calcOffsetsTo(c),
361 b = t+el.offsetHeight,
362 r = l+el.offsetWidth;
364 var ch = c.clientHeight;
365 var ct = parseInt(c.scrollTop, 10);
366 var cl = parseInt(c.scrollLeft, 10);
368 var cr = cl + c.clientWidth;
376 if(hscroll !== false){
380 c.scrollLeft = r-c.clientWidth;
387 scrollChildIntoView : function(child, hscroll){
388 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
392 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
393 * the new height may not be available immediately.
394 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
395 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
396 * @param {Function} onComplete (optional) Function to call when animation completes
397 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
398 * @return {Roo.Element} this
400 autoHeight : function(animate, duration, onComplete, easing){
401 var oldHeight = this.getHeight();
403 this.setHeight(1); // force clipping
404 setTimeout(function(){
405 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
407 this.setHeight(height);
409 if(typeof onComplete == "function"){
413 this.setHeight(oldHeight); // restore original height
414 this.setHeight(height, animate, duration, function(){
416 if(typeof onComplete == "function") { onComplete(); }
417 }.createDelegate(this), easing);
419 }.createDelegate(this), 0);
424 * Returns true if this element is an ancestor of the passed element
425 * @param {HTMLElement/String} el The element to check
426 * @return {Boolean} True if this element is an ancestor of el, else false
428 contains : function(el){
429 if(!el){return false;}
430 return D.isAncestor(this.dom, el.dom ? el.dom : el);
434 * Checks whether the element is currently visible using both visibility and display properties.
435 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
436 * @return {Boolean} True if the element is currently visible, else false
438 isVisible : function(deep) {
439 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
440 if(deep !== true || !vis){
443 var p = this.dom.parentNode;
444 while(p && p.tagName.toLowerCase() != "body"){
445 if(!Roo.fly(p, '_isVisible').isVisible()){
454 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
455 * @param {String} selector The CSS selector
456 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
457 * @return {CompositeElement/CompositeElementLite} The composite element
459 select : function(selector, unique){
460 return El.select(selector, unique, this.dom);
464 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
465 * @param {String} selector The CSS selector
466 * @return {Array} An array of the matched nodes
468 query : function(selector, unique){
469 return Roo.DomQuery.select(selector, this.dom);
473 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
474 * @param {String} selector The CSS selector
475 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
476 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
478 child : function(selector, returnDom){
479 var n = Roo.DomQuery.selectNode(selector, this.dom);
480 return returnDom ? n : Roo.get(n);
484 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
485 * @param {String} selector The CSS selector
486 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
487 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
489 down : function(selector, returnDom){
490 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
491 return returnDom ? n : Roo.get(n);
495 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
496 * @param {String} group The group the DD object is member of
497 * @param {Object} config The DD config object
498 * @param {Object} overrides An object containing methods to override/implement on the DD object
499 * @return {Roo.dd.DD} The DD object
501 initDD : function(group, config, overrides){
502 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
503 return Roo.apply(dd, overrides);
507 * Initializes a {@link Roo.dd.DDProxy} object for this element.
508 * @param {String} group The group the DDProxy object is member of
509 * @param {Object} config The DDProxy config object
510 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
511 * @return {Roo.dd.DDProxy} The DDProxy object
513 initDDProxy : function(group, config, overrides){
514 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
515 return Roo.apply(dd, overrides);
519 * Initializes a {@link Roo.dd.DDTarget} object for this element.
520 * @param {String} group The group the DDTarget object is member of
521 * @param {Object} config The DDTarget config object
522 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
523 * @return {Roo.dd.DDTarget} The DDTarget object
525 initDDTarget : function(group, config, overrides){
526 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
527 return Roo.apply(dd, overrides);
531 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
532 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
533 * @param {Boolean} visible Whether the element is visible
534 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
535 * @return {Roo.Element} this
537 setVisible : function(visible, animate){
539 if(this.visibilityMode == El.DISPLAY){
540 this.setDisplayed(visible);
543 this.dom.style.visibility = visible ? "visible" : "hidden";
546 // closure for composites
548 var visMode = this.visibilityMode;
550 this.setOpacity(.01);
551 this.setVisible(true);
553 this.anim({opacity: { to: (visible?1:0) }},
554 this.preanim(arguments, 1),
555 null, .35, 'easeIn', function(){
557 if(visMode == El.DISPLAY){
558 dom.style.display = "none";
560 dom.style.visibility = "hidden";
562 Roo.get(dom).setOpacity(1);
570 * Returns true if display is not "none"
573 isDisplayed : function() {
574 return this.getStyle("display") != "none";
578 * Toggles the element's visibility or display, depending on visibility mode.
579 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
580 * @return {Roo.Element} this
582 toggle : function(animate){
583 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
588 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
589 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
590 * @return {Roo.Element} this
592 setDisplayed : function(value) {
593 if(typeof value == "boolean"){
594 value = value ? this.originalDisplay : "none";
596 this.setStyle("display", value);
601 * Tries to focus the element. Any exceptions are caught and ignored.
602 * @return {Roo.Element} this
612 * Tries to blur the element. Any exceptions are caught and ignored.
613 * @return {Roo.Element} this
623 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
624 * @param {String/Array} className The CSS class to add, or an array of classes
625 * @return {Roo.Element} this
627 addClass : function(className){
628 if(className instanceof Array){
629 for(var i = 0, len = className.length; i < len; i++) {
630 this.addClass(className[i]);
633 if(className && !this.hasClass(className)){
634 this.dom.className = this.dom.className + " " + className;
641 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
642 * @param {String/Array} className The CSS class to add, or an array of classes
643 * @return {Roo.Element} this
645 radioClass : function(className){
646 var siblings = this.dom.parentNode.childNodes;
647 for(var i = 0; i < siblings.length; i++) {
650 Roo.get(s).removeClass(className);
653 this.addClass(className);
658 * Removes one or more CSS classes from the element.
659 * @param {String/Array} className The CSS class to remove, or an array of classes
660 * @return {Roo.Element} this
662 removeClass : function(className){
663 if(!className || !this.dom.className){
666 if(className instanceof Array){
667 for(var i = 0, len = className.length; i < len; i++) {
668 this.removeClass(className[i]);
671 if(this.hasClass(className)){
672 var re = this.classReCache[className];
674 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
675 this.classReCache[className] = re;
678 this.dom.className.replace(re, " ");
688 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
689 * @param {String} className The CSS class to toggle
690 * @return {Roo.Element} this
692 toggleClass : function(className){
693 if(this.hasClass(className)){
694 this.removeClass(className);
696 this.addClass(className);
702 * Checks if the specified CSS class exists on this element's DOM node.
703 * @param {String} className The CSS class to check for
704 * @return {Boolean} True if the class exists, else false
706 hasClass : function(className){
707 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
711 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
712 * @param {String} oldClassName The CSS class to replace
713 * @param {String} newClassName The replacement CSS class
714 * @return {Roo.Element} this
716 replaceClass : function(oldClassName, newClassName){
717 this.removeClass(oldClassName);
718 this.addClass(newClassName);
723 * Returns an object with properties matching the styles requested.
724 * For example, el.getStyles('color', 'font-size', 'width') might return
725 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
726 * @param {String} style1 A style name
727 * @param {String} style2 A style name
728 * @param {String} etc.
729 * @return {Object} The style object
731 getStyles : function(){
732 var a = arguments, len = a.length, r = {};
733 for(var i = 0; i < len; i++){
734 r[a[i]] = this.getStyle(a[i]);
740 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
741 * @param {String} property The style property whose value is returned.
742 * @return {String} The current value of the style property for this element.
744 getStyle : function(){
745 return view && view.getComputedStyle ?
747 var el = this.dom, v, cs, camel;
751 if(el.style && (v = el.style[prop])){
754 if(cs = view.getComputedStyle(el, "")){
755 if(!(camel = propCache[prop])){
756 camel = propCache[prop] = prop.replace(camelRe, camelFn);
763 var el = this.dom, v, cs, camel;
764 if(prop == 'opacity'){
765 if(typeof el.style.filter == 'string'){
766 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
768 var fv = parseFloat(m[1]);
770 return fv ? fv / 100 : 0;
775 }else if(prop == 'float'){
778 if(!(camel = propCache[prop])){
779 camel = propCache[prop] = prop.replace(camelRe, camelFn);
781 if(v = el.style[camel]){
784 if(cs = el.currentStyle){
792 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
793 * @param {String/Object} property The style property to be set, or an object of multiple styles.
794 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
795 * @return {Roo.Element} this
797 setStyle : function(prop, value){
798 if(typeof prop == "string"){
800 if (prop == 'float') {
801 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
806 if(!(camel = propCache[prop])){
807 camel = propCache[prop] = prop.replace(camelRe, camelFn);
810 if(camel == 'opacity') {
811 this.setOpacity(value);
813 this.dom.style[camel] = value;
816 for(var style in prop){
817 if(typeof prop[style] != "function"){
818 this.setStyle(style, prop[style]);
826 * More flexible version of {@link #setStyle} for setting style properties.
827 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
828 * a function which returns such a specification.
829 * @return {Roo.Element} this
831 applyStyles : function(style){
832 Roo.DomHelper.applyStyles(this.dom, style);
837 * 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).
838 * @return {Number} The X position of the element
841 return D.getX(this.dom);
845 * 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).
846 * @return {Number} The Y position of the element
849 return D.getY(this.dom);
853 * 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).
854 * @return {Array} The XY position of the element
857 return D.getXY(this.dom);
861 * 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).
862 * @param {Number} The X position of the element
863 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
864 * @return {Roo.Element} this
866 setX : function(x, animate){
870 this.setXY([x, this.getY()], this.preanim(arguments, 1));
876 * 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).
877 * @param {Number} The Y position of the element
878 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
879 * @return {Roo.Element} this
881 setY : function(y, animate){
885 this.setXY([this.getX(), y], this.preanim(arguments, 1));
891 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
892 * @param {String} left The left CSS property value
893 * @return {Roo.Element} this
895 setLeft : function(left){
896 this.setStyle("left", this.addUnits(left));
901 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
902 * @param {String} top The top CSS property value
903 * @return {Roo.Element} this
905 setTop : function(top){
906 this.setStyle("top", this.addUnits(top));
911 * Sets the element's CSS right style.
912 * @param {String} right The right CSS property value
913 * @return {Roo.Element} this
915 setRight : function(right){
916 this.setStyle("right", this.addUnits(right));
921 * Sets the element's CSS bottom style.
922 * @param {String} bottom The bottom CSS property value
923 * @return {Roo.Element} this
925 setBottom : function(bottom){
926 this.setStyle("bottom", this.addUnits(bottom));
931 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
932 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
933 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
934 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
935 * @return {Roo.Element} this
937 setXY : function(pos, animate){
939 D.setXY(this.dom, pos);
941 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
947 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
948 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
949 * @param {Number} x X value for new position (coordinates are page-based)
950 * @param {Number} y Y value for new position (coordinates are page-based)
951 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
952 * @return {Roo.Element} this
954 setLocation : function(x, y, animate){
955 this.setXY([x, y], this.preanim(arguments, 2));
960 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
961 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
962 * @param {Number} x X value for new position (coordinates are page-based)
963 * @param {Number} y Y value for new position (coordinates are page-based)
964 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
965 * @return {Roo.Element} this
967 moveTo : function(x, y, animate){
968 this.setXY([x, y], this.preanim(arguments, 2));
973 * Returns the region of the given element.
974 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
975 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
977 getRegion : function(){
978 return D.getRegion(this.dom);
982 * Returns the offset height of the element
983 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
984 * @return {Number} The element's height
986 getHeight : function(contentHeight){
987 var h = this.dom.offsetHeight || 0;
988 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
992 * Returns the offset width of the element
993 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
994 * @return {Number} The element's width
996 getWidth : function(contentWidth){
997 var w = this.dom.offsetWidth || 0;
998 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
1002 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
1003 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
1004 * if a height has not been set using CSS.
1007 getComputedHeight : function(){
1008 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
1010 h = parseInt(this.getStyle('height'), 10) || 0;
1011 if(!this.isBorderBox()){
1012 h += this.getFrameWidth('tb');
1019 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1020 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1021 * if a width has not been set using CSS.
1024 getComputedWidth : function(){
1025 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1027 w = parseInt(this.getStyle('width'), 10) || 0;
1028 if(!this.isBorderBox()){
1029 w += this.getFrameWidth('lr');
1036 * Returns the size of the element.
1037 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1038 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1040 getSize : function(contentSize){
1041 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1045 * Returns the width and height of the viewport.
1046 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1048 getViewSize : function(){
1049 var d = this.dom, doc = document, aw = 0, ah = 0;
1050 if(d == doc || d == doc.body){
1051 return {width : D.getViewWidth(), height: D.getViewHeight()};
1054 width : d.clientWidth,
1055 height: d.clientHeight
1061 * Returns the value of the "value" attribute
1062 * @param {Boolean} asNumber true to parse the value as a number
1063 * @return {String/Number}
1065 getValue : function(asNumber){
1066 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1070 adjustWidth : function(width){
1071 if(typeof width == "number"){
1072 if(this.autoBoxAdjust && !this.isBorderBox()){
1073 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1083 adjustHeight : function(height){
1084 if(typeof height == "number"){
1085 if(this.autoBoxAdjust && !this.isBorderBox()){
1086 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1096 * Set the width of the element
1097 * @param {Number} width The new width
1098 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1099 * @return {Roo.Element} this
1101 setWidth : function(width, animate){
1102 width = this.adjustWidth(width);
1104 this.dom.style.width = this.addUnits(width);
1106 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1112 * Set the height of the element
1113 * @param {Number} height The new height
1114 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1115 * @return {Roo.Element} this
1117 setHeight : function(height, animate){
1118 height = this.adjustHeight(height);
1120 this.dom.style.height = this.addUnits(height);
1122 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1128 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
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 setSize : function(width, height, animate){
1135 if(typeof width == "object"){ // in case of object from getSize()
1136 height = width.height; width = width.width;
1138 width = this.adjustWidth(width); height = this.adjustHeight(height);
1140 this.dom.style.width = this.addUnits(width);
1141 this.dom.style.height = this.addUnits(height);
1143 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1149 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1150 * @param {Number} x X value for new position (coordinates are page-based)
1151 * @param {Number} y Y value for new position (coordinates are page-based)
1152 * @param {Number} width The new width
1153 * @param {Number} height The new height
1154 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1155 * @return {Roo.Element} this
1157 setBounds : function(x, y, width, height, animate){
1159 this.setSize(width, height);
1160 this.setLocation(x, y);
1162 width = this.adjustWidth(width); height = this.adjustHeight(height);
1163 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1164 this.preanim(arguments, 4), 'motion');
1170 * 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.
1171 * @param {Roo.lib.Region} region The region to fill
1172 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1173 * @return {Roo.Element} this
1175 setRegion : function(region, animate){
1176 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1181 * Appends an event handler
1183 * @param {String} eventName The type of event to append
1184 * @param {Function} fn The method the event invokes
1185 * @param {Object} scope (optional) The scope (this object) of the fn
1186 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1188 addListener : function(eventName, fn, scope, options){
1190 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1195 * Removes an event handler from this element
1196 * @param {String} eventName the type of event to remove
1197 * @param {Function} fn the method the event invokes
1198 * @return {Roo.Element} this
1200 removeListener : function(eventName, fn){
1201 Roo.EventManager.removeListener(this.dom, eventName, fn);
1206 * Removes all previous added listeners from this element
1207 * @return {Roo.Element} this
1209 removeAllListeners : function(){
1210 E.purgeElement(this.dom);
1214 relayEvent : function(eventName, observable){
1215 this.on(eventName, function(e){
1216 observable.fireEvent(eventName, e);
1221 * Set the opacity of the element
1222 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1223 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1224 * @return {Roo.Element} this
1226 setOpacity : function(opacity, animate){
1228 var s = this.dom.style;
1231 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1232 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1234 s.opacity = opacity;
1237 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1243 * Gets the left X coordinate
1244 * @param {Boolean} local True to get the local css position instead of page coordinate
1247 getLeft : function(local){
1251 return parseInt(this.getStyle("left"), 10) || 0;
1256 * Gets the right X coordinate of the element (element X position + element width)
1257 * @param {Boolean} local True to get the local css position instead of page coordinate
1260 getRight : function(local){
1262 return this.getX() + this.getWidth();
1264 return (this.getLeft(true) + this.getWidth()) || 0;
1269 * Gets the top Y coordinate
1270 * @param {Boolean} local True to get the local css position instead of page coordinate
1273 getTop : function(local) {
1277 return parseInt(this.getStyle("top"), 10) || 0;
1282 * Gets the bottom Y coordinate of the element (element Y position + element height)
1283 * @param {Boolean} local True to get the local css position instead of page coordinate
1286 getBottom : function(local){
1288 return this.getY() + this.getHeight();
1290 return (this.getTop(true) + this.getHeight()) || 0;
1295 * Initializes positioning on this element. If a desired position is not passed, it will make the
1296 * the element positioned relative IF it is not already positioned.
1297 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1298 * @param {Number} zIndex (optional) The zIndex to apply
1299 * @param {Number} x (optional) Set the page X position
1300 * @param {Number} y (optional) Set the page Y position
1302 position : function(pos, zIndex, x, y){
1304 if(this.getStyle('position') == 'static'){
1305 this.setStyle('position', 'relative');
1308 this.setStyle("position", pos);
1311 this.setStyle("z-index", zIndex);
1313 if(x !== undefined && y !== undefined){
1315 }else if(x !== undefined){
1317 }else if(y !== undefined){
1323 * Clear positioning back to the default when the document was loaded
1324 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1325 * @return {Roo.Element} this
1327 clearPositioning : function(value){
1335 "position" : "static"
1341 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1342 * snapshot before performing an update and then restoring the element.
1345 getPositioning : function(){
1346 var l = this.getStyle("left");
1347 var t = this.getStyle("top");
1349 "position" : this.getStyle("position"),
1351 "right" : l ? "" : this.getStyle("right"),
1353 "bottom" : t ? "" : this.getStyle("bottom"),
1354 "z-index" : this.getStyle("z-index")
1359 * Gets the width of the border(s) for the specified side(s)
1360 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1361 * passing lr would get the border (l)eft width + the border (r)ight width.
1362 * @return {Number} The width of the sides passed added together
1364 getBorderWidth : function(side){
1365 return this.addStyles(side, El.borders);
1369 * Gets the width of the padding(s) for the specified side(s)
1370 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1371 * passing lr would get the padding (l)eft + the padding (r)ight.
1372 * @return {Number} The padding of the sides passed added together
1374 getPadding : function(side){
1375 return this.addStyles(side, El.paddings);
1379 * Set positioning with an object returned by getPositioning().
1380 * @param {Object} posCfg
1381 * @return {Roo.Element} this
1383 setPositioning : function(pc){
1384 this.applyStyles(pc);
1385 if(pc.right == "auto"){
1386 this.dom.style.right = "";
1388 if(pc.bottom == "auto"){
1389 this.dom.style.bottom = "";
1395 fixDisplay : function(){
1396 if(this.getStyle("display") == "none"){
1397 this.setStyle("visibility", "hidden");
1398 this.setStyle("display", this.originalDisplay); // first try reverting to default
1399 if(this.getStyle("display") == "none"){ // if that fails, default to block
1400 this.setStyle("display", "block");
1406 * Quick set left and top adding default units
1407 * @param {String} left The left CSS property value
1408 * @param {String} top The top CSS property value
1409 * @return {Roo.Element} this
1411 setLeftTop : function(left, top){
1412 this.dom.style.left = this.addUnits(left);
1413 this.dom.style.top = this.addUnits(top);
1418 * Move this element relative to its current position.
1419 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1420 * @param {Number} distance How far to move the element in pixels
1421 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1422 * @return {Roo.Element} this
1424 move : function(direction, distance, animate){
1425 var xy = this.getXY();
1426 direction = direction.toLowerCase();
1430 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1434 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1439 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1444 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1451 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1452 * @return {Roo.Element} this
1455 if(!this.isClipped){
1456 this.isClipped = true;
1457 this.originalClip = {
1458 "o": this.getStyle("overflow"),
1459 "x": this.getStyle("overflow-x"),
1460 "y": this.getStyle("overflow-y")
1462 this.setStyle("overflow", "hidden");
1463 this.setStyle("overflow-x", "hidden");
1464 this.setStyle("overflow-y", "hidden");
1470 * Return clipping (overflow) to original clipping before clip() was called
1471 * @return {Roo.Element} this
1473 unclip : function(){
1475 this.isClipped = false;
1476 var o = this.originalClip;
1477 if(o.o){this.setStyle("overflow", o.o);}
1478 if(o.x){this.setStyle("overflow-x", o.x);}
1479 if(o.y){this.setStyle("overflow-y", o.y);}
1486 * Gets the x,y coordinates specified by the anchor position on the element.
1487 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1488 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1489 * {width: (target width), height: (target height)} (defaults to the element's current size)
1490 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1491 * @return {Array} [x, y] An array containing the element's x and y coordinates
1493 getAnchorXY : function(anchor, local, s){
1494 //Passing a different size is useful for pre-calculating anchors,
1495 //especially for anchored animations that change the el size.
1497 var w, h, vp = false;
1500 if(d == document.body || d == document){
1502 w = D.getViewWidth(); h = D.getViewHeight();
1504 w = this.getWidth(); h = this.getHeight();
1507 w = s.width; h = s.height;
1509 var x = 0, y = 0, r = Math.round;
1510 switch((anchor || "tl").toLowerCase()){
1552 var sc = this.getScroll();
1553 return [x + sc.left, y + sc.top];
1555 //Add the element's offset xy
1556 var o = this.getXY();
1557 return [x+o[0], y+o[1]];
1561 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1562 * supported position values.
1563 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1564 * @param {String} position The position to align to.
1565 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1566 * @return {Array} [x, y]
1568 getAlignToXY : function(el, p, o){
1572 throw "Element.alignTo with an element that doesn't exist";
1574 var c = false; //constrain to viewport
1575 var p1 = "", p2 = "";
1582 }else if(p.indexOf("-") == -1){
1585 p = p.toLowerCase();
1586 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1588 throw "Element.alignTo with an invalid alignment " + p;
1590 p1 = m[1]; p2 = m[2]; c = !!m[3];
1592 //Subtract the aligned el's internal xy from the target's offset xy
1593 //plus custom offset to get the aligned el's new offset xy
1594 var a1 = this.getAnchorXY(p1, true);
1595 var a2 = el.getAnchorXY(p2, false);
1596 var x = a2[0] - a1[0] + o[0];
1597 var y = a2[1] - a1[1] + o[1];
1599 //constrain the aligned el to viewport if necessary
1600 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1601 // 5px of margin for ie
1602 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1604 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1605 //perpendicular to the vp border, allow the aligned el to slide on that border,
1606 //otherwise swap the aligned el to the opposite border of the target.
1607 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1608 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1609 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1610 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1613 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1614 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1616 if((x+w) > dw + scrollX){
1617 x = swapX ? r.left-w : dw+scrollX-w;
1620 x = swapX ? r.right : scrollX;
1622 if((y+h) > dh + scrollY){
1623 y = swapY ? r.top-h : dh+scrollY-h;
1626 y = swapY ? r.bottom : scrollY;
1633 getConstrainToXY : function(){
1634 var os = {top:0, left:0, bottom:0, right: 0};
1636 return function(el, local, offsets, proposedXY){
1638 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1640 var vw, vh, vx = 0, vy = 0;
1641 if(el.dom == document.body || el.dom == document){
1642 vw = Roo.lib.Dom.getViewWidth();
1643 vh = Roo.lib.Dom.getViewHeight();
1645 vw = el.dom.clientWidth;
1646 vh = el.dom.clientHeight;
1648 var vxy = el.getXY();
1654 var s = el.getScroll();
1656 vx += offsets.left + s.left;
1657 vy += offsets.top + s.top;
1659 vw -= offsets.right;
1660 vh -= offsets.bottom;
1665 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1666 var x = xy[0], y = xy[1];
1667 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1669 // only move it if it needs it
1672 // first validate right/bottom
1681 // then make sure top/left isn't negative
1690 return moved ? [x, y] : false;
1695 adjustForConstraints : function(xy, parent, offsets){
1696 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1700 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1701 * document it aligns it to the viewport.
1702 * The position parameter is optional, and can be specified in any one of the following formats:
1704 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1705 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1706 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1707 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1708 * <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
1709 * element's anchor point, and the second value is used as the target's anchor point.</li>
1711 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1712 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1713 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1714 * that specified in order to enforce the viewport constraints.
1715 * Following are all of the supported anchor positions:
1718 ----- -----------------------------
1719 tl The top left corner (default)
1720 t The center of the top edge
1721 tr The top right corner
1722 l The center of the left edge
1723 c In the center of the element
1724 r The center of the right edge
1725 bl The bottom left corner
1726 b The center of the bottom edge
1727 br The bottom right corner
1731 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1732 el.alignTo("other-el");
1734 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1735 el.alignTo("other-el", "tr?");
1737 // align the bottom right corner of el with the center left edge of other-el
1738 el.alignTo("other-el", "br-l?");
1740 // align the center of el with the bottom left corner of other-el and
1741 // adjust the x position by -6 pixels (and the y position by 0)
1742 el.alignTo("other-el", "c-bl", [-6, 0]);
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 * @return {Roo.Element} this
1750 alignTo : function(element, position, offsets, animate){
1751 var xy = this.getAlignToXY(element, position, offsets);
1752 this.setXY(xy, this.preanim(arguments, 3));
1757 * Anchors an element to another element and realigns it when the window is resized.
1758 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1759 * @param {String} position The position to align to.
1760 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1761 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1762 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1763 * is a number, it is used as the buffer delay (defaults to 50ms).
1764 * @param {Function} callback The function to call after the animation finishes
1765 * @return {Roo.Element} this
1767 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1768 var action = function(){
1769 this.alignTo(el, alignment, offsets, animate);
1770 Roo.callback(callback, this);
1772 Roo.EventManager.onWindowResize(action, this);
1773 var tm = typeof monitorScroll;
1774 if(tm != 'undefined'){
1775 Roo.EventManager.on(window, 'scroll', action, this,
1776 {buffer: tm == 'number' ? monitorScroll : 50});
1778 action.call(this); // align immediately
1782 * Clears any opacity settings from this element. Required in some cases for IE.
1783 * @return {Roo.Element} this
1785 clearOpacity : function(){
1786 if (window.ActiveXObject) {
1787 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1788 this.dom.style.filter = "";
1791 this.dom.style.opacity = "";
1792 this.dom.style["-moz-opacity"] = "";
1793 this.dom.style["-khtml-opacity"] = "";
1799 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1800 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1801 * @return {Roo.Element} this
1803 hide : function(animate){
1804 this.setVisible(false, this.preanim(arguments, 0));
1809 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1810 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1811 * @return {Roo.Element} this
1813 show : function(animate){
1814 this.setVisible(true, this.preanim(arguments, 0));
1819 * @private Test if size has a unit, otherwise appends the default
1821 addUnits : function(size){
1822 return Roo.Element.addUnits(size, this.defaultUnit);
1826 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1827 * @return {Roo.Element} this
1829 beginMeasure : function(){
1831 if(el.offsetWidth || el.offsetHeight){
1832 return this; // offsets work already
1835 var p = this.dom, b = document.body; // start with this element
1836 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1837 var pe = Roo.get(p);
1838 if(pe.getStyle('display') == 'none'){
1839 changed.push({el: p, visibility: pe.getStyle("visibility")});
1840 p.style.visibility = "hidden";
1841 p.style.display = "block";
1845 this._measureChanged = changed;
1851 * Restores displays to before beginMeasure was called
1852 * @return {Roo.Element} this
1854 endMeasure : function(){
1855 var changed = this._measureChanged;
1857 for(var i = 0, len = changed.length; i < len; i++) {
1859 r.el.style.visibility = r.visibility;
1860 r.el.style.display = "none";
1862 this._measureChanged = null;
1868 * Update the innerHTML of this element, optionally searching for and processing scripts
1869 * @param {String} html The new HTML
1870 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1871 * @param {Function} callback For async script loading you can be noticed when the update completes
1872 * @return {Roo.Element} this
1874 update : function(html, loadScripts, callback){
1875 if(typeof html == "undefined"){
1878 if(loadScripts !== true){
1879 this.dom.innerHTML = html;
1880 if(typeof callback == "function"){
1888 html += '<span id="' + id + '"></span>';
1890 E.onAvailable(id, function(){
1891 var hd = document.getElementsByTagName("head")[0];
1892 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1893 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1894 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1897 while(match = re.exec(html)){
1898 var attrs = match[1];
1899 var srcMatch = attrs ? attrs.match(srcRe) : false;
1900 if(srcMatch && srcMatch[2]){
1901 var s = document.createElement("script");
1902 s.src = srcMatch[2];
1903 var typeMatch = attrs.match(typeRe);
1904 if(typeMatch && typeMatch[2]){
1905 s.type = typeMatch[2];
1908 }else if(match[2] && match[2].length > 0){
1909 if(window.execScript) {
1910 window.execScript(match[2]);
1918 window.eval(match[2]);
1922 var el = document.getElementById(id);
1923 if(el){el.parentNode.removeChild(el);}
1924 if(typeof callback == "function"){
1928 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1933 * Direct access to the UpdateManager update() method (takes the same parameters).
1934 * @param {String/Function} url The url for this request or a function to call to get the url
1935 * @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}
1936 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1937 * @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.
1938 * @return {Roo.Element} this
1941 var um = this.getUpdateManager();
1942 um.update.apply(um, arguments);
1947 * Gets this element's UpdateManager
1948 * @return {Roo.UpdateManager} The UpdateManager
1950 getUpdateManager : function(){
1951 if(!this.updateManager){
1952 this.updateManager = new Roo.UpdateManager(this);
1954 return this.updateManager;
1958 * Disables text selection for this element (normalized across browsers)
1959 * @return {Roo.Element} this
1961 unselectable : function(){
1962 this.dom.unselectable = "on";
1963 this.swallowEvent("selectstart", true);
1964 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1965 this.addClass("x-unselectable");
1970 * Calculates the x, y to center this element on the screen
1971 * @return {Array} The x, y values [x, y]
1973 getCenterXY : function(){
1974 return this.getAlignToXY(document, 'c-c');
1978 * Centers the Element in either the viewport, or another Element.
1979 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1981 center : function(centerIn){
1982 this.alignTo(centerIn || document, 'c-c');
1987 * Tests various css rules/browsers to determine if this element uses a border box
1990 isBorderBox : function(){
1991 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1995 * Return a box {x, y, width, height} that can be used to set another elements
1996 * size/location to match this element.
1997 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1998 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1999 * @return {Object} box An object in the format {x, y, width, height}
2001 getBox : function(contentBox, local){
2006 var left = parseInt(this.getStyle("left"), 10) || 0;
2007 var top = parseInt(this.getStyle("top"), 10) || 0;
2010 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
2012 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
2014 var l = this.getBorderWidth("l")+this.getPadding("l");
2015 var r = this.getBorderWidth("r")+this.getPadding("r");
2016 var t = this.getBorderWidth("t")+this.getPadding("t");
2017 var b = this.getBorderWidth("b")+this.getPadding("b");
2018 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)};
2020 bx.right = bx.x + bx.width;
2021 bx.bottom = bx.y + bx.height;
2026 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2027 for more information about the sides.
2028 * @param {String} sides
2031 getFrameWidth : function(sides, onlyContentBox){
2032 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2036 * 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.
2037 * @param {Object} box The box to fill {x, y, width, height}
2038 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2039 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2040 * @return {Roo.Element} this
2042 setBox : function(box, adjust, animate){
2043 var w = box.width, h = box.height;
2044 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2045 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2046 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2048 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2053 * Forces the browser to repaint this element
2054 * @return {Roo.Element} this
2056 repaint : function(){
2058 this.addClass("x-repaint");
2059 setTimeout(function(){
2060 Roo.get(dom).removeClass("x-repaint");
2066 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2067 * then it returns the calculated width of the sides (see getPadding)
2068 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2069 * @return {Object/Number}
2071 getMargins : function(side){
2074 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2075 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2076 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2077 right: parseInt(this.getStyle("margin-right"), 10) || 0
2080 return this.addStyles(side, El.margins);
2085 addStyles : function(sides, styles){
2087 for(var i = 0, len = sides.length; i < len; i++){
2088 v = this.getStyle(styles[sides.charAt(i)]);
2090 w = parseInt(v, 10);
2098 * Creates a proxy element of this element
2099 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2100 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2101 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2102 * @return {Roo.Element} The new proxy element
2104 createProxy : function(config, renderTo, matchBox){
2106 renderTo = Roo.getDom(renderTo);
2108 renderTo = document.body;
2110 config = typeof config == "object" ?
2111 config : {tag : "div", cls: config};
2112 var proxy = Roo.DomHelper.append(renderTo, config, true);
2114 proxy.setBox(this.getBox());
2120 * Puts a mask over this element to disable user interaction. Requires core.css.
2121 * This method can only be applied to elements which accept child nodes.
2122 * @param {String} msg (optional) A message to display in the mask
2123 * @param {String} msgCls (optional) A css class to apply to the msg element
2124 * @return {Element} The mask element
2126 mask : function(msg, msgCls)
2128 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2129 this.setStyle("position", "relative");
2132 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2134 this.addClass("x-masked");
2135 this._mask.setDisplayed(true);
2140 while (dom && dom.style) {
2141 if (!isNaN(parseInt(dom.style.zIndex))) {
2142 z = Math.max(z, parseInt(dom.style.zIndex));
2144 dom = dom.parentNode;
2146 // if we are masking the body - then it hides everything..
2147 if (this.dom == document.body) {
2149 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2150 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2153 if(typeof msg == 'string'){
2155 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2157 var mm = this._maskMsg;
2158 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2159 if (mm.dom.firstChild) { // weird IE issue?
2160 mm.dom.firstChild.innerHTML = msg;
2162 mm.setDisplayed(true);
2164 mm.setStyle('z-index', z + 102);
2166 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2167 this._mask.setHeight(this.getHeight());
2169 this._mask.setStyle('z-index', z + 100);
2175 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2176 * it is cached for reuse.
2178 unmask : function(removeEl){
2180 if(removeEl === true){
2181 this._mask.remove();
2184 this._maskMsg.remove();
2185 delete this._maskMsg;
2188 this._mask.setDisplayed(false);
2190 this._maskMsg.setDisplayed(false);
2194 this.removeClass("x-masked");
2198 * Returns true if this element is masked
2201 isMasked : function(){
2202 return this._mask && this._mask.isVisible();
2206 * Creates an iframe shim for this element to keep selects and other windowed objects from
2208 * @return {Roo.Element} The new shim element
2210 createShim : function(){
2211 var el = document.createElement('iframe');
2212 el.frameBorder = 'no';
2213 el.className = 'roo-shim';
2214 if(Roo.isIE && Roo.isSecure){
2215 el.src = Roo.SSL_SECURE_URL;
2217 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2218 shim.autoBoxAdjust = false;
2223 * Removes this element from the DOM and deletes it from the cache
2225 remove : function(){
2226 if(this.dom.parentNode){
2227 this.dom.parentNode.removeChild(this.dom);
2229 delete El.cache[this.dom.id];
2233 * Sets up event handlers to add and remove a css class when the mouse is over this element
2234 * @param {String} className
2235 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2236 * mouseout events for children elements
2237 * @return {Roo.Element} this
2239 addClassOnOver : function(className, preventFlicker){
2240 this.on("mouseover", function(){
2241 Roo.fly(this, '_internal').addClass(className);
2243 var removeFn = function(e){
2244 if(preventFlicker !== true || !e.within(this, true)){
2245 Roo.fly(this, '_internal').removeClass(className);
2248 this.on("mouseout", removeFn, this.dom);
2253 * Sets up event handlers to add and remove a css class when this element has the focus
2254 * @param {String} className
2255 * @return {Roo.Element} this
2257 addClassOnFocus : function(className){
2258 this.on("focus", function(){
2259 Roo.fly(this, '_internal').addClass(className);
2261 this.on("blur", function(){
2262 Roo.fly(this, '_internal').removeClass(className);
2267 * 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)
2268 * @param {String} className
2269 * @return {Roo.Element} this
2271 addClassOnClick : function(className){
2273 this.on("mousedown", function(){
2274 Roo.fly(dom, '_internal').addClass(className);
2275 var d = Roo.get(document);
2276 var fn = function(){
2277 Roo.fly(dom, '_internal').removeClass(className);
2278 d.removeListener("mouseup", fn);
2280 d.on("mouseup", fn);
2286 * Stops the specified event from bubbling and optionally prevents the default action
2287 * @param {String} eventName
2288 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2289 * @return {Roo.Element} this
2291 swallowEvent : function(eventName, preventDefault){
2292 var fn = function(e){
2293 e.stopPropagation();
2298 if(eventName instanceof Array){
2299 for(var i = 0, len = eventName.length; i < len; i++){
2300 this.on(eventName[i], fn);
2304 this.on(eventName, fn);
2311 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2314 * Sizes this element to its parent element's dimensions performing
2315 * neccessary box adjustments.
2316 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2317 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2318 * @return {Roo.Element} this
2320 fitToParent : function(monitorResize, targetParent) {
2321 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2322 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2323 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2326 var p = Roo.get(targetParent || this.dom.parentNode);
2327 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2328 if (monitorResize === true) {
2329 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2330 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2336 * Gets the next sibling, skipping text nodes
2337 * @return {HTMLElement} The next sibling or null
2339 getNextSibling : function(){
2340 var n = this.dom.nextSibling;
2341 while(n && n.nodeType != 1){
2348 * Gets the previous sibling, skipping text nodes
2349 * @return {HTMLElement} The previous sibling or null
2351 getPrevSibling : function(){
2352 var n = this.dom.previousSibling;
2353 while(n && n.nodeType != 1){
2354 n = n.previousSibling;
2361 * Appends the passed element(s) to this element
2362 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2363 * @return {Roo.Element} this
2365 appendChild: function(el){
2372 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2373 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2374 * automatically generated with the specified attributes.
2375 * @param {HTMLElement} insertBefore (optional) a child element of this element
2376 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2377 * @return {Roo.Element} The new child element
2379 createChild: function(config, insertBefore, returnDom){
2380 config = config || {tag:'div'};
2382 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2384 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2388 * Appends this element to the passed element
2389 * @param {String/HTMLElement/Element} el The new parent element
2390 * @return {Roo.Element} this
2392 appendTo: function(el){
2393 el = Roo.getDom(el);
2394 el.appendChild(this.dom);
2399 * Inserts this element before the passed element in the DOM
2400 * @param {String/HTMLElement/Element} el The element to insert before
2401 * @return {Roo.Element} this
2403 insertBefore: function(el){
2404 el = Roo.getDom(el);
2405 el.parentNode.insertBefore(this.dom, el);
2410 * Inserts this element after the passed element in the DOM
2411 * @param {String/HTMLElement/Element} el The element to insert after
2412 * @return {Roo.Element} this
2414 insertAfter: function(el){
2415 el = Roo.getDom(el);
2416 el.parentNode.insertBefore(this.dom, el.nextSibling);
2421 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2422 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2423 * @return {Roo.Element} The new child
2425 insertFirst: function(el, returnDom){
2427 if(typeof el == 'object' && !el.nodeType){ // dh config
2428 return this.createChild(el, this.dom.firstChild, returnDom);
2430 el = Roo.getDom(el);
2431 this.dom.insertBefore(el, this.dom.firstChild);
2432 return !returnDom ? Roo.get(el) : el;
2437 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2438 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2439 * @param {String} where (optional) 'before' or 'after' defaults to before
2440 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2441 * @return {Roo.Element} the inserted Element
2443 insertSibling: function(el, where, returnDom){
2444 where = where ? where.toLowerCase() : 'before';
2446 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2448 if(typeof el == 'object' && !el.nodeType){ // dh config
2449 if(where == 'after' && !this.dom.nextSibling){
2450 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2452 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2456 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2457 where == 'before' ? this.dom : this.dom.nextSibling);
2466 * Creates and wraps this element with another element
2467 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2468 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2469 * @return {HTMLElement/Element} The newly created wrapper element
2471 wrap: function(config, returnDom){
2473 config = {tag: "div"};
2475 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2476 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2481 * Replaces the passed element with this element
2482 * @param {String/HTMLElement/Element} el The element to replace
2483 * @return {Roo.Element} this
2485 replace: function(el){
2487 this.insertBefore(el);
2493 * Inserts an html fragment into this element
2494 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2495 * @param {String} html The HTML fragment
2496 * @param {Boolean} returnEl True to return an Roo.Element
2497 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2499 insertHtml : function(where, html, returnEl){
2500 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2501 return returnEl ? Roo.get(el) : el;
2505 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2506 * @param {Object} o The object with the attributes
2507 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2508 * @return {Roo.Element} this
2510 set : function(o, useSet){
2512 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2514 if(attr == "style" || typeof o[attr] == "function") { continue; }
2516 el.className = o["cls"];
2519 el.setAttribute(attr, o[attr]);
2526 Roo.DomHelper.applyStyles(el, o.style);
2532 * Convenience method for constructing a KeyMap
2533 * @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:
2534 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2535 * @param {Function} fn The function to call
2536 * @param {Object} scope (optional) The scope of the function
2537 * @return {Roo.KeyMap} The KeyMap created
2539 addKeyListener : function(key, fn, scope){
2541 if(typeof key != "object" || key instanceof Array){
2557 return new Roo.KeyMap(this, config);
2561 * Creates a KeyMap for this element
2562 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2563 * @return {Roo.KeyMap} The KeyMap created
2565 addKeyMap : function(config){
2566 return new Roo.KeyMap(this, config);
2570 * Returns true if this element is scrollable.
2573 isScrollable : function(){
2575 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2579 * 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().
2580 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2581 * @param {Number} value The new scroll value
2582 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2583 * @return {Element} this
2586 scrollTo : function(side, value, animate){
2587 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2589 this.dom[prop] = value;
2591 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2592 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2598 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2599 * within this element's scrollable range.
2600 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2601 * @param {Number} distance How far to scroll the element in pixels
2602 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2603 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2604 * was scrolled as far as it could go.
2606 scroll : function(direction, distance, animate){
2607 if(!this.isScrollable()){
2611 var l = el.scrollLeft, t = el.scrollTop;
2612 var w = el.scrollWidth, h = el.scrollHeight;
2613 var cw = el.clientWidth, ch = el.clientHeight;
2614 direction = direction.toLowerCase();
2615 var scrolled = false;
2616 var a = this.preanim(arguments, 2);
2621 var v = Math.min(l + distance, w-cw);
2622 this.scrollTo("left", v, a);
2629 var v = Math.max(l - distance, 0);
2630 this.scrollTo("left", v, a);
2638 var v = Math.max(t - distance, 0);
2639 this.scrollTo("top", v, a);
2647 var v = Math.min(t + distance, h-ch);
2648 this.scrollTo("top", v, a);
2657 * Translates the passed page coordinates into left/top css values for this element
2658 * @param {Number/Array} x The page x or an array containing [x, y]
2659 * @param {Number} y The page y
2660 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2662 translatePoints : function(x, y){
2663 if(typeof x == 'object' || x instanceof Array){
2666 var p = this.getStyle('position');
2667 var o = this.getXY();
2669 var l = parseInt(this.getStyle('left'), 10);
2670 var t = parseInt(this.getStyle('top'), 10);
2673 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2676 t = (p == "relative") ? 0 : this.dom.offsetTop;
2679 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2683 * Returns the current scroll position of the element.
2684 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2686 getScroll : function(){
2687 var d = this.dom, doc = document;
2688 if(d == doc || d == doc.body){
2689 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2690 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2691 return {left: l, top: t};
2693 return {left: d.scrollLeft, top: d.scrollTop};
2698 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2699 * are convert to standard 6 digit hex color.
2700 * @param {String} attr The css attribute
2701 * @param {String} defaultValue The default value to use when a valid color isn't found
2702 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2705 getColor : function(attr, defaultValue, prefix){
2706 var v = this.getStyle(attr);
2707 if(!v || v == "transparent" || v == "inherit") {
2708 return defaultValue;
2710 var color = typeof prefix == "undefined" ? "#" : prefix;
2711 if(v.substr(0, 4) == "rgb("){
2712 var rvs = v.slice(4, v.length -1).split(",");
2713 for(var i = 0; i < 3; i++){
2714 var h = parseInt(rvs[i]).toString(16);
2721 if(v.substr(0, 1) == "#"){
2723 for(var i = 1; i < 4; i++){
2724 var c = v.charAt(i);
2727 }else if(v.length == 7){
2728 color += v.substr(1);
2732 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2736 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2737 * gradient background, rounded corners and a 4-way shadow.
2738 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2739 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2740 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2741 * @return {Roo.Element} this
2743 boxWrap : function(cls){
2744 cls = cls || 'x-box';
2745 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2746 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2751 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2752 * @param {String} namespace The namespace in which to look for the attribute
2753 * @param {String} name The attribute name
2754 * @return {String} The attribute value
2756 getAttributeNS : Roo.isIE ? function(ns, name){
2758 var type = typeof d[ns+":"+name];
2759 if(type != 'undefined' && type != 'unknown'){
2760 return d[ns+":"+name];
2763 } : function(ns, name){
2765 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2770 * Sets or Returns the value the dom attribute value
2771 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2772 * @param {String} value (optional) The value to set the attribute to
2773 * @return {String} The attribute value
2775 attr : function(name){
2776 if (arguments.length > 1) {
2777 this.dom.setAttribute(name, arguments[1]);
2778 return arguments[1];
2780 if (typeof(name) == 'object') {
2781 for(var i in name) {
2782 this.attr(i, name[i]);
2788 if (!this.dom.hasAttribute(name)) {
2791 return this.dom.getAttribute(name);
2798 var ep = El.prototype;
2801 * Appends an event handler (Shorthand for addListener)
2802 * @param {String} eventName The type of event to append
2803 * @param {Function} fn The method the event invokes
2804 * @param {Object} scope (optional) The scope (this object) of the fn
2805 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2808 ep.on = ep.addListener;
2810 ep.mon = ep.addListener;
2813 * Removes an event handler from this element (shorthand for removeListener)
2814 * @param {String} eventName the type of event to remove
2815 * @param {Function} fn the method the event invokes
2816 * @return {Roo.Element} this
2819 ep.un = ep.removeListener;
2822 * true to automatically adjust width and height settings for box-model issues (default to true)
2824 ep.autoBoxAdjust = true;
2827 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2830 El.addUnits = function(v, defaultUnit){
2831 if(v === "" || v == "auto"){
2834 if(v === undefined){
2837 if(typeof v == "number" || !El.unitPattern.test(v)){
2838 return v + (defaultUnit || 'px');
2843 // special markup used throughout Roo when box wrapping elements
2844 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>';
2846 * Visibility mode constant - Use visibility to hide element
2852 * Visibility mode constant - Use display to hide element
2858 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2859 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2860 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2872 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2873 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2874 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2875 * @return {Element} The Element object
2878 El.get = function(el){
2880 if(!el){ return null; }
2881 if(typeof el == "string"){ // element id
2882 if(!(elm = document.getElementById(el))){
2885 if(ex = El.cache[el]){
2888 ex = El.cache[el] = new El(elm);
2891 }else if(el.tagName){ // dom element
2895 if(ex = El.cache[id]){
2898 ex = El.cache[id] = new El(el);
2901 }else if(el instanceof El){
2903 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2904 // catch case where it hasn't been appended
2905 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2908 }else if(el.isComposite){
2910 }else if(el instanceof Array){
2911 return El.select(el);
2912 }else if(el == document){
2913 // create a bogus element object representing the document object
2915 var f = function(){};
2916 f.prototype = El.prototype;
2918 docEl.dom = document;
2926 El.uncache = function(el){
2927 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2929 delete El.cache[a[i].id || a[i]];
2935 // Garbage collection - uncache elements/purge listeners on orphaned elements
2936 // so we don't hold a reference and cause the browser to retain them
2937 El.garbageCollect = function(){
2938 if(!Roo.enableGarbageCollector){
2939 clearInterval(El.collectorThread);
2942 for(var eid in El.cache){
2943 var el = El.cache[eid], d = el.dom;
2944 // -------------------------------------------------------
2945 // Determining what is garbage:
2946 // -------------------------------------------------------
2948 // dom node is null, definitely garbage
2949 // -------------------------------------------------------
2951 // no parentNode == direct orphan, definitely garbage
2952 // -------------------------------------------------------
2953 // !d.offsetParent && !document.getElementById(eid)
2954 // display none elements have no offsetParent so we will
2955 // also try to look it up by it's id. However, check
2956 // offsetParent first so we don't do unneeded lookups.
2957 // This enables collection of elements that are not orphans
2958 // directly, but somewhere up the line they have an orphan
2960 // -------------------------------------------------------
2961 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2962 delete El.cache[eid];
2963 if(d && Roo.enableListenerCollection){
2969 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2973 El.Flyweight = function(dom){
2976 El.Flyweight.prototype = El.prototype;
2978 El._flyweights = {};
2980 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2981 * the dom node can be overwritten by other code.
2982 * @param {String/HTMLElement} el The dom node or id
2983 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2984 * prevent conflicts (e.g. internally Roo uses "_internal")
2986 * @return {Element} The shared Element object
2988 El.fly = function(el, named){
2989 named = named || '_global';
2990 el = Roo.getDom(el);
2994 if(!El._flyweights[named]){
2995 El._flyweights[named] = new El.Flyweight();
2997 El._flyweights[named].dom = el;
2998 return El._flyweights[named];
3002 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
3003 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
3004 * Shorthand of {@link Roo.Element#get}
3005 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
3006 * @return {Element} The Element object
3012 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3013 * the dom node can be overwritten by other code.
3014 * Shorthand of {@link Roo.Element#fly}
3015 * @param {String/HTMLElement} el The dom node or id
3016 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3017 * prevent conflicts (e.g. internally Roo uses "_internal")
3019 * @return {Element} The shared Element object
3025 // speedy lookup for elements never to box adjust
3026 var noBoxAdjust = Roo.isStrict ? {
3029 input:1, select:1, textarea:1
3031 if(Roo.isIE || Roo.isGecko){
3032 noBoxAdjust['button'] = 1;
3036 Roo.EventManager.on(window, 'unload', function(){
3038 delete El._flyweights;
3046 Roo.Element.selectorFunction = Roo.DomQuery.select;
3049 Roo.Element.select = function(selector, unique, root){
3051 if(typeof selector == "string"){
3052 els = Roo.Element.selectorFunction(selector, root);
3053 }else if(selector.length !== undefined){
3056 throw "Invalid selector";
3058 if(unique === true){
3059 return new Roo.CompositeElement(els);
3061 return new Roo.CompositeElementLite(els);
3065 * Selects elements based on the passed CSS selector to enable working on them as 1.
3066 * @param {String/Array} selector The CSS selector or an array of elements
3067 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3068 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3069 * @return {CompositeElementLite/CompositeElement}
3073 Roo.select = Roo.Element.select;