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'
210 el = Roo.get(el.dom.parentNode);
212 // 'findparent:'+ JSON.stringify(el, null, 4)+
213 // ' | scrollable: '+el.isScrollable()+
214 // ' | D height: '+D.getViewHeight() +
215 // ' | D width: '+D.getViewWidth() +
216 // ' | el height: '+el.dom.clientHeight+
217 // ' | el width: '+el.dom.clientWidth+
222 if(!el.isScrollable()){
230 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
231 * This is a shortcut for findParentNode() that always returns an Roo.Element.
232 * @param {String} selector The simple selector to test
233 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
234 search as a number or element (defaults to 10 || document.body)
235 * @return {Roo.Element} The matching DOM node (or null if no match was found)
237 up : function(simpleSelector, maxDepth){
238 return this.findParentNode(simpleSelector, maxDepth, true);
244 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
245 * @param {String} selector The simple selector to test
246 * @return {Boolean} True if this element matches the selector, else false
248 is : function(simpleSelector){
249 return Roo.DomQuery.is(this.dom, simpleSelector);
253 * Perform animation on this element.
254 * @param {Object} args The YUI animation control args
255 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
256 * @param {Function} onComplete (optional) Function to call when animation completes
257 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
258 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
259 * @return {Roo.Element} this
261 animate : function(args, duration, onComplete, easing, animType){
262 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
267 * @private Internal animation call
269 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
270 animType = animType || 'run';
272 var anim = Roo.lib.Anim[animType](
274 (opt.duration || defaultDur) || .35,
275 (opt.easing || defaultEase) || 'easeOut',
277 Roo.callback(cb, this);
278 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
286 // private legacy anim prep
287 preanim : function(a, i){
288 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
292 * Removes worthless text nodes
293 * @param {Boolean} forceReclean (optional) By default the element
294 * keeps track if it has been cleaned already so
295 * you can call this over and over. However, if you update the element and
296 * need to force a reclean, you can pass true.
298 clean : function(forceReclean){
299 if(this.isCleaned && forceReclean !== true){
303 var d = this.dom, n = d.firstChild, ni = -1;
305 var nx = n.nextSibling;
306 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
313 this.isCleaned = true;
318 calcOffsetsTo : function(el){
321 var restorePos = false;
322 if(el.getStyle('position') == 'static'){
323 el.position('relative');
328 while(op && op != d && op.tagName != 'HTML'){
331 op = op.offsetParent;
334 el.position('static');
340 * Scrolls this element into view within the passed container.
341 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
342 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
343 * @return {Roo.Element} this
345 scrollIntoView : function(container, hscroll){
346 var c = Roo.getDom(container) || document.body;
349 var o = this.calcOffsetsTo(c),
352 b = t+el.offsetHeight,
353 r = l+el.offsetWidth;
355 var ch = c.clientHeight;
356 var ct = parseInt(c.scrollTop, 10);
357 var cl = parseInt(c.scrollLeft, 10);
359 var cr = cl + c.clientWidth;
367 if(hscroll !== false){
371 c.scrollLeft = r-c.clientWidth;
378 scrollChildIntoView : function(child, hscroll){
379 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
383 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
384 * the new height may not be available immediately.
385 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
386 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
387 * @param {Function} onComplete (optional) Function to call when animation completes
388 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
389 * @return {Roo.Element} this
391 autoHeight : function(animate, duration, onComplete, easing){
392 var oldHeight = this.getHeight();
394 this.setHeight(1); // force clipping
395 setTimeout(function(){
396 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
398 this.setHeight(height);
400 if(typeof onComplete == "function"){
404 this.setHeight(oldHeight); // restore original height
405 this.setHeight(height, animate, duration, function(){
407 if(typeof onComplete == "function") { onComplete(); }
408 }.createDelegate(this), easing);
410 }.createDelegate(this), 0);
415 * Returns true if this element is an ancestor of the passed element
416 * @param {HTMLElement/String} el The element to check
417 * @return {Boolean} True if this element is an ancestor of el, else false
419 contains : function(el){
420 if(!el){return false;}
421 return D.isAncestor(this.dom, el.dom ? el.dom : el);
425 * Checks whether the element is currently visible using both visibility and display properties.
426 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
427 * @return {Boolean} True if the element is currently visible, else false
429 isVisible : function(deep) {
430 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
431 if(deep !== true || !vis){
434 var p = this.dom.parentNode;
435 while(p && p.tagName.toLowerCase() != "body"){
436 if(!Roo.fly(p, '_isVisible').isVisible()){
445 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
446 * @param {String} selector The CSS selector
447 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
448 * @return {CompositeElement/CompositeElementLite} The composite element
450 select : function(selector, unique){
451 return El.select(selector, unique, this.dom);
455 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
456 * @param {String} selector The CSS selector
457 * @return {Array} An array of the matched nodes
459 query : function(selector, unique){
460 return Roo.DomQuery.select(selector, this.dom);
464 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
465 * @param {String} selector The CSS selector
466 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
467 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
469 child : function(selector, returnDom){
470 var n = Roo.DomQuery.selectNode(selector, this.dom);
471 return returnDom ? n : Roo.get(n);
475 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
476 * @param {String} selector The CSS selector
477 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
478 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
480 down : function(selector, returnDom){
481 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
482 return returnDom ? n : Roo.get(n);
486 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
487 * @param {String} group The group the DD object is member of
488 * @param {Object} config The DD config object
489 * @param {Object} overrides An object containing methods to override/implement on the DD object
490 * @return {Roo.dd.DD} The DD object
492 initDD : function(group, config, overrides){
493 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
494 return Roo.apply(dd, overrides);
498 * Initializes a {@link Roo.dd.DDProxy} object for this element.
499 * @param {String} group The group the DDProxy object is member of
500 * @param {Object} config The DDProxy config object
501 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
502 * @return {Roo.dd.DDProxy} The DDProxy object
504 initDDProxy : function(group, config, overrides){
505 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
506 return Roo.apply(dd, overrides);
510 * Initializes a {@link Roo.dd.DDTarget} object for this element.
511 * @param {String} group The group the DDTarget object is member of
512 * @param {Object} config The DDTarget config object
513 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
514 * @return {Roo.dd.DDTarget} The DDTarget object
516 initDDTarget : function(group, config, overrides){
517 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
518 return Roo.apply(dd, overrides);
522 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
523 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
524 * @param {Boolean} visible Whether the element is visible
525 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
526 * @return {Roo.Element} this
528 setVisible : function(visible, animate){
530 if(this.visibilityMode == El.DISPLAY){
531 this.setDisplayed(visible);
534 this.dom.style.visibility = visible ? "visible" : "hidden";
537 // closure for composites
539 var visMode = this.visibilityMode;
541 this.setOpacity(.01);
542 this.setVisible(true);
544 this.anim({opacity: { to: (visible?1:0) }},
545 this.preanim(arguments, 1),
546 null, .35, 'easeIn', function(){
548 if(visMode == El.DISPLAY){
549 dom.style.display = "none";
551 dom.style.visibility = "hidden";
553 Roo.get(dom).setOpacity(1);
561 * Returns true if display is not "none"
564 isDisplayed : function() {
565 return this.getStyle("display") != "none";
569 * Toggles the element's visibility or display, depending on visibility mode.
570 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
571 * @return {Roo.Element} this
573 toggle : function(animate){
574 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
579 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
580 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
581 * @return {Roo.Element} this
583 setDisplayed : function(value) {
584 if(typeof value == "boolean"){
585 value = value ? this.originalDisplay : "none";
587 this.setStyle("display", value);
592 * Tries to focus the element. Any exceptions are caught and ignored.
593 * @return {Roo.Element} this
603 * Tries to blur the element. Any exceptions are caught and ignored.
604 * @return {Roo.Element} this
614 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
615 * @param {String/Array} className The CSS class to add, or an array of classes
616 * @return {Roo.Element} this
618 addClass : function(className){
619 if(className instanceof Array){
620 for(var i = 0, len = className.length; i < len; i++) {
621 this.addClass(className[i]);
624 if(className && !this.hasClass(className)){
625 this.dom.className = this.dom.className + " " + className;
632 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
633 * @param {String/Array} className The CSS class to add, or an array of classes
634 * @return {Roo.Element} this
636 radioClass : function(className){
637 var siblings = this.dom.parentNode.childNodes;
638 for(var i = 0; i < siblings.length; i++) {
641 Roo.get(s).removeClass(className);
644 this.addClass(className);
649 * Removes one or more CSS classes from the element.
650 * @param {String/Array} className The CSS class to remove, or an array of classes
651 * @return {Roo.Element} this
653 removeClass : function(className){
654 if(!className || !this.dom.className){
657 if(className instanceof Array){
658 for(var i = 0, len = className.length; i < len; i++) {
659 this.removeClass(className[i]);
662 if(this.hasClass(className)){
663 var re = this.classReCache[className];
665 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
666 this.classReCache[className] = re;
669 this.dom.className.replace(re, " ");
679 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
680 * @param {String} className The CSS class to toggle
681 * @return {Roo.Element} this
683 toggleClass : function(className){
684 if(this.hasClass(className)){
685 this.removeClass(className);
687 this.addClass(className);
693 * Checks if the specified CSS class exists on this element's DOM node.
694 * @param {String} className The CSS class to check for
695 * @return {Boolean} True if the class exists, else false
697 hasClass : function(className){
698 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
702 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
703 * @param {String} oldClassName The CSS class to replace
704 * @param {String} newClassName The replacement CSS class
705 * @return {Roo.Element} this
707 replaceClass : function(oldClassName, newClassName){
708 this.removeClass(oldClassName);
709 this.addClass(newClassName);
714 * Returns an object with properties matching the styles requested.
715 * For example, el.getStyles('color', 'font-size', 'width') might return
716 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
717 * @param {String} style1 A style name
718 * @param {String} style2 A style name
719 * @param {String} etc.
720 * @return {Object} The style object
722 getStyles : function(){
723 var a = arguments, len = a.length, r = {};
724 for(var i = 0; i < len; i++){
725 r[a[i]] = this.getStyle(a[i]);
731 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
732 * @param {String} property The style property whose value is returned.
733 * @return {String} The current value of the style property for this element.
735 getStyle : function(){
736 return view && view.getComputedStyle ?
738 var el = this.dom, v, cs, camel;
742 if(el.style && (v = el.style[prop])){
745 if(cs = view.getComputedStyle(el, "")){
746 if(!(camel = propCache[prop])){
747 camel = propCache[prop] = prop.replace(camelRe, camelFn);
754 var el = this.dom, v, cs, camel;
755 if(prop == 'opacity'){
756 if(typeof el.style.filter == 'string'){
757 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
759 var fv = parseFloat(m[1]);
761 return fv ? fv / 100 : 0;
766 }else if(prop == 'float'){
769 if(!(camel = propCache[prop])){
770 camel = propCache[prop] = prop.replace(camelRe, camelFn);
772 if(v = el.style[camel]){
775 if(cs = el.currentStyle){
783 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
784 * @param {String/Object} property The style property to be set, or an object of multiple styles.
785 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
786 * @return {Roo.Element} this
788 setStyle : function(prop, value){
789 if(typeof prop == "string"){
791 if (prop == 'float') {
792 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
797 if(!(camel = propCache[prop])){
798 camel = propCache[prop] = prop.replace(camelRe, camelFn);
801 if(camel == 'opacity') {
802 this.setOpacity(value);
804 this.dom.style[camel] = value;
807 for(var style in prop){
808 if(typeof prop[style] != "function"){
809 this.setStyle(style, prop[style]);
817 * More flexible version of {@link #setStyle} for setting style properties.
818 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
819 * a function which returns such a specification.
820 * @return {Roo.Element} this
822 applyStyles : function(style){
823 Roo.DomHelper.applyStyles(this.dom, style);
828 * 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).
829 * @return {Number} The X position of the element
832 return D.getX(this.dom);
836 * 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).
837 * @return {Number} The Y position of the element
840 return D.getY(this.dom);
844 * 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).
845 * @return {Array} The XY position of the element
848 return D.getXY(this.dom);
852 * 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).
853 * @param {Number} The X position of the element
854 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
855 * @return {Roo.Element} this
857 setX : function(x, animate){
861 this.setXY([x, this.getY()], this.preanim(arguments, 1));
867 * 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).
868 * @param {Number} The Y position of the element
869 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
870 * @return {Roo.Element} this
872 setY : function(y, animate){
876 this.setXY([this.getX(), y], this.preanim(arguments, 1));
882 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
883 * @param {String} left The left CSS property value
884 * @return {Roo.Element} this
886 setLeft : function(left){
887 this.setStyle("left", this.addUnits(left));
892 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
893 * @param {String} top The top CSS property value
894 * @return {Roo.Element} this
896 setTop : function(top){
897 this.setStyle("top", this.addUnits(top));
902 * Sets the element's CSS right style.
903 * @param {String} right The right CSS property value
904 * @return {Roo.Element} this
906 setRight : function(right){
907 this.setStyle("right", this.addUnits(right));
912 * Sets the element's CSS bottom style.
913 * @param {String} bottom The bottom CSS property value
914 * @return {Roo.Element} this
916 setBottom : function(bottom){
917 this.setStyle("bottom", this.addUnits(bottom));
922 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
923 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
924 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
925 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
926 * @return {Roo.Element} this
928 setXY : function(pos, animate){
930 D.setXY(this.dom, pos);
932 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
938 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
939 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
940 * @param {Number} x X value for new position (coordinates are page-based)
941 * @param {Number} y Y value for new position (coordinates are page-based)
942 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
943 * @return {Roo.Element} this
945 setLocation : function(x, y, animate){
946 this.setXY([x, y], this.preanim(arguments, 2));
951 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
952 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
953 * @param {Number} x X value for new position (coordinates are page-based)
954 * @param {Number} y Y value for new position (coordinates are page-based)
955 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
956 * @return {Roo.Element} this
958 moveTo : function(x, y, animate){
959 this.setXY([x, y], this.preanim(arguments, 2));
964 * Returns the region of the given element.
965 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
966 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
968 getRegion : function(){
969 return D.getRegion(this.dom);
973 * Returns the offset height of the element
974 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
975 * @return {Number} The element's height
977 getHeight : function(contentHeight){
978 var h = this.dom.offsetHeight || 0;
979 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
983 * Returns the offset width of the element
984 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
985 * @return {Number} The element's width
987 getWidth : function(contentWidth){
988 var w = this.dom.offsetWidth || 0;
989 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
993 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
994 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
995 * if a height has not been set using CSS.
998 getComputedHeight : function(){
999 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
1001 h = parseInt(this.getStyle('height'), 10) || 0;
1002 if(!this.isBorderBox()){
1003 h += this.getFrameWidth('tb');
1010 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1011 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1012 * if a width has not been set using CSS.
1015 getComputedWidth : function(){
1016 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1018 w = parseInt(this.getStyle('width'), 10) || 0;
1019 if(!this.isBorderBox()){
1020 w += this.getFrameWidth('lr');
1027 * Returns the size of the element.
1028 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1029 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1031 getSize : function(contentSize){
1032 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1036 * Returns the width and height of the viewport.
1037 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1039 getViewSize : function(){
1040 var d = this.dom, doc = document, aw = 0, ah = 0;
1041 if(d == doc || d == doc.body){
1042 return {width : D.getViewWidth(), height: D.getViewHeight()};
1045 width : d.clientWidth,
1046 height: d.clientHeight
1052 * Returns the value of the "value" attribute
1053 * @param {Boolean} asNumber true to parse the value as a number
1054 * @return {String/Number}
1056 getValue : function(asNumber){
1057 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1061 adjustWidth : function(width){
1062 if(typeof width == "number"){
1063 if(this.autoBoxAdjust && !this.isBorderBox()){
1064 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1074 adjustHeight : function(height){
1075 if(typeof height == "number"){
1076 if(this.autoBoxAdjust && !this.isBorderBox()){
1077 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1087 * Set the width of the element
1088 * @param {Number} width The new width
1089 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1090 * @return {Roo.Element} this
1092 setWidth : function(width, animate){
1093 width = this.adjustWidth(width);
1095 this.dom.style.width = this.addUnits(width);
1097 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1103 * Set the height of the element
1104 * @param {Number} height The new height
1105 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1106 * @return {Roo.Element} this
1108 setHeight : function(height, animate){
1109 height = this.adjustHeight(height);
1111 this.dom.style.height = this.addUnits(height);
1113 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1119 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1120 * @param {Number} width The new width
1121 * @param {Number} height The new height
1122 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1123 * @return {Roo.Element} this
1125 setSize : function(width, height, animate){
1126 if(typeof width == "object"){ // in case of object from getSize()
1127 height = width.height; width = width.width;
1129 width = this.adjustWidth(width); height = this.adjustHeight(height);
1131 this.dom.style.width = this.addUnits(width);
1132 this.dom.style.height = this.addUnits(height);
1134 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1140 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1141 * @param {Number} x X value for new position (coordinates are page-based)
1142 * @param {Number} y Y value for new position (coordinates are page-based)
1143 * @param {Number} width The new width
1144 * @param {Number} height The new height
1145 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1146 * @return {Roo.Element} this
1148 setBounds : function(x, y, width, height, animate){
1150 this.setSize(width, height);
1151 this.setLocation(x, y);
1153 width = this.adjustWidth(width); height = this.adjustHeight(height);
1154 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1155 this.preanim(arguments, 4), 'motion');
1161 * 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.
1162 * @param {Roo.lib.Region} region The region to fill
1163 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1164 * @return {Roo.Element} this
1166 setRegion : function(region, animate){
1167 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1172 * Appends an event handler
1174 * @param {String} eventName The type of event to append
1175 * @param {Function} fn The method the event invokes
1176 * @param {Object} scope (optional) The scope (this object) of the fn
1177 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1179 addListener : function(eventName, fn, scope, options){
1181 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1186 * Removes an event handler from this element
1187 * @param {String} eventName the type of event to remove
1188 * @param {Function} fn the method the event invokes
1189 * @return {Roo.Element} this
1191 removeListener : function(eventName, fn){
1192 Roo.EventManager.removeListener(this.dom, eventName, fn);
1197 * Removes all previous added listeners from this element
1198 * @return {Roo.Element} this
1200 removeAllListeners : function(){
1201 E.purgeElement(this.dom);
1205 relayEvent : function(eventName, observable){
1206 this.on(eventName, function(e){
1207 observable.fireEvent(eventName, e);
1212 * Set the opacity of the element
1213 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1214 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1215 * @return {Roo.Element} this
1217 setOpacity : function(opacity, animate){
1219 var s = this.dom.style;
1222 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1223 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1225 s.opacity = opacity;
1228 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1234 * Gets the left X coordinate
1235 * @param {Boolean} local True to get the local css position instead of page coordinate
1238 getLeft : function(local){
1242 return parseInt(this.getStyle("left"), 10) || 0;
1247 * Gets the right X coordinate of the element (element X position + element width)
1248 * @param {Boolean} local True to get the local css position instead of page coordinate
1251 getRight : function(local){
1253 return this.getX() + this.getWidth();
1255 return (this.getLeft(true) + this.getWidth()) || 0;
1260 * Gets the top Y coordinate
1261 * @param {Boolean} local True to get the local css position instead of page coordinate
1264 getTop : function(local) {
1268 return parseInt(this.getStyle("top"), 10) || 0;
1273 * Gets the bottom Y coordinate of the element (element Y position + element height)
1274 * @param {Boolean} local True to get the local css position instead of page coordinate
1277 getBottom : function(local){
1279 return this.getY() + this.getHeight();
1281 return (this.getTop(true) + this.getHeight()) || 0;
1286 * Initializes positioning on this element. If a desired position is not passed, it will make the
1287 * the element positioned relative IF it is not already positioned.
1288 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1289 * @param {Number} zIndex (optional) The zIndex to apply
1290 * @param {Number} x (optional) Set the page X position
1291 * @param {Number} y (optional) Set the page Y position
1293 position : function(pos, zIndex, x, y){
1295 if(this.getStyle('position') == 'static'){
1296 this.setStyle('position', 'relative');
1299 this.setStyle("position", pos);
1302 this.setStyle("z-index", zIndex);
1304 if(x !== undefined && y !== undefined){
1306 }else if(x !== undefined){
1308 }else if(y !== undefined){
1314 * Clear positioning back to the default when the document was loaded
1315 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1316 * @return {Roo.Element} this
1318 clearPositioning : function(value){
1326 "position" : "static"
1332 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1333 * snapshot before performing an update and then restoring the element.
1336 getPositioning : function(){
1337 var l = this.getStyle("left");
1338 var t = this.getStyle("top");
1340 "position" : this.getStyle("position"),
1342 "right" : l ? "" : this.getStyle("right"),
1344 "bottom" : t ? "" : this.getStyle("bottom"),
1345 "z-index" : this.getStyle("z-index")
1350 * Gets the width of the border(s) for the specified side(s)
1351 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1352 * passing lr would get the border (l)eft width + the border (r)ight width.
1353 * @return {Number} The width of the sides passed added together
1355 getBorderWidth : function(side){
1356 return this.addStyles(side, El.borders);
1360 * Gets the width of the padding(s) for the specified side(s)
1361 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1362 * passing lr would get the padding (l)eft + the padding (r)ight.
1363 * @return {Number} The padding of the sides passed added together
1365 getPadding : function(side){
1366 return this.addStyles(side, El.paddings);
1370 * Set positioning with an object returned by getPositioning().
1371 * @param {Object} posCfg
1372 * @return {Roo.Element} this
1374 setPositioning : function(pc){
1375 this.applyStyles(pc);
1376 if(pc.right == "auto"){
1377 this.dom.style.right = "";
1379 if(pc.bottom == "auto"){
1380 this.dom.style.bottom = "";
1386 fixDisplay : function(){
1387 if(this.getStyle("display") == "none"){
1388 this.setStyle("visibility", "hidden");
1389 this.setStyle("display", this.originalDisplay); // first try reverting to default
1390 if(this.getStyle("display") == "none"){ // if that fails, default to block
1391 this.setStyle("display", "block");
1397 * Quick set left and top adding default units
1398 * @param {String} left The left CSS property value
1399 * @param {String} top The top CSS property value
1400 * @return {Roo.Element} this
1402 setLeftTop : function(left, top){
1403 this.dom.style.left = this.addUnits(left);
1404 this.dom.style.top = this.addUnits(top);
1409 * Move this element relative to its current position.
1410 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1411 * @param {Number} distance How far to move the element in pixels
1412 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1413 * @return {Roo.Element} this
1415 move : function(direction, distance, animate){
1416 var xy = this.getXY();
1417 direction = direction.toLowerCase();
1421 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1425 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1430 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1435 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1442 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1443 * @return {Roo.Element} this
1446 if(!this.isClipped){
1447 this.isClipped = true;
1448 this.originalClip = {
1449 "o": this.getStyle("overflow"),
1450 "x": this.getStyle("overflow-x"),
1451 "y": this.getStyle("overflow-y")
1453 this.setStyle("overflow", "hidden");
1454 this.setStyle("overflow-x", "hidden");
1455 this.setStyle("overflow-y", "hidden");
1461 * Return clipping (overflow) to original clipping before clip() was called
1462 * @return {Roo.Element} this
1464 unclip : function(){
1466 this.isClipped = false;
1467 var o = this.originalClip;
1468 if(o.o){this.setStyle("overflow", o.o);}
1469 if(o.x){this.setStyle("overflow-x", o.x);}
1470 if(o.y){this.setStyle("overflow-y", o.y);}
1477 * Gets the x,y coordinates specified by the anchor position on the element.
1478 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1479 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1480 * {width: (target width), height: (target height)} (defaults to the element's current size)
1481 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1482 * @return {Array} [x, y] An array containing the element's x and y coordinates
1484 getAnchorXY : function(anchor, local, s){
1485 //Passing a different size is useful for pre-calculating anchors,
1486 //especially for anchored animations that change the el size.
1488 var w, h, vp = false;
1491 if(d == document.body || d == document){
1493 w = D.getViewWidth(); h = D.getViewHeight();
1495 w = this.getWidth(); h = this.getHeight();
1498 w = s.width; h = s.height;
1500 var x = 0, y = 0, r = Math.round;
1501 switch((anchor || "tl").toLowerCase()){
1543 var sc = this.getScroll();
1544 return [x + sc.left, y + sc.top];
1546 //Add the element's offset xy
1547 var o = this.getXY();
1548 return [x+o[0], y+o[1]];
1552 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1553 * supported position values.
1554 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1555 * @param {String} position The position to align to.
1556 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1557 * @return {Array} [x, y]
1559 getAlignToXY : function(el, p, o){
1563 throw "Element.alignTo with an element that doesn't exist";
1565 var c = false; //constrain to viewport
1566 var p1 = "", p2 = "";
1573 }else if(p.indexOf("-") == -1){
1576 p = p.toLowerCase();
1577 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1579 throw "Element.alignTo with an invalid alignment " + p;
1581 p1 = m[1]; p2 = m[2]; c = !!m[3];
1583 //Subtract the aligned el's internal xy from the target's offset xy
1584 //plus custom offset to get the aligned el's new offset xy
1585 var a1 = this.getAnchorXY(p1, true);
1586 var a2 = el.getAnchorXY(p2, false);
1587 var x = a2[0] - a1[0] + o[0];
1588 var y = a2[1] - a1[1] + o[1];
1590 //constrain the aligned el to viewport if necessary
1591 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1592 // 5px of margin for ie
1593 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1595 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1596 //perpendicular to the vp border, allow the aligned el to slide on that border,
1597 //otherwise swap the aligned el to the opposite border of the target.
1598 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1599 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1600 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1601 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1604 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1605 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1607 if((x+w) > dw + scrollX){
1608 x = swapX ? r.left-w : dw+scrollX-w;
1611 x = swapX ? r.right : scrollX;
1613 if((y+h) > dh + scrollY){
1614 y = swapY ? r.top-h : dh+scrollY-h;
1617 y = swapY ? r.bottom : scrollY;
1624 getConstrainToXY : function(){
1625 var os = {top:0, left:0, bottom:0, right: 0};
1627 return function(el, local, offsets, proposedXY){
1629 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1631 var vw, vh, vx = 0, vy = 0;
1632 if(el.dom == document.body || el.dom == document){
1633 vw = Roo.lib.Dom.getViewWidth();
1634 vh = Roo.lib.Dom.getViewHeight();
1636 vw = el.dom.clientWidth;
1637 vh = el.dom.clientHeight;
1639 var vxy = el.getXY();
1645 var s = el.getScroll();
1647 vx += offsets.left + s.left;
1648 vy += offsets.top + s.top;
1650 vw -= offsets.right;
1651 vh -= offsets.bottom;
1656 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1657 var x = xy[0], y = xy[1];
1658 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1660 // only move it if it needs it
1663 // first validate right/bottom
1672 // then make sure top/left isn't negative
1681 return moved ? [x, y] : false;
1686 adjustForConstraints : function(xy, parent, offsets){
1687 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1691 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1692 * document it aligns it to the viewport.
1693 * The position parameter is optional, and can be specified in any one of the following formats:
1695 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1696 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1697 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1698 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1699 * <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
1700 * element's anchor point, and the second value is used as the target's anchor point.</li>
1702 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1703 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1704 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1705 * that specified in order to enforce the viewport constraints.
1706 * Following are all of the supported anchor positions:
1709 ----- -----------------------------
1710 tl The top left corner (default)
1711 t The center of the top edge
1712 tr The top right corner
1713 l The center of the left edge
1714 c In the center of the element
1715 r The center of the right edge
1716 bl The bottom left corner
1717 b The center of the bottom edge
1718 br The bottom right corner
1722 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1723 el.alignTo("other-el");
1725 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1726 el.alignTo("other-el", "tr?");
1728 // align the bottom right corner of el with the center left edge of other-el
1729 el.alignTo("other-el", "br-l?");
1731 // align the center of el with the bottom left corner of other-el and
1732 // adjust the x position by -6 pixels (and the y position by 0)
1733 el.alignTo("other-el", "c-bl", [-6, 0]);
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 * @return {Roo.Element} this
1741 alignTo : function(element, position, offsets, animate){
1742 var xy = this.getAlignToXY(element, position, offsets);
1743 this.setXY(xy, this.preanim(arguments, 3));
1748 * Anchors an element to another element and realigns it when the window is resized.
1749 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1750 * @param {String} position The position to align to.
1751 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1752 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1753 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1754 * is a number, it is used as the buffer delay (defaults to 50ms).
1755 * @param {Function} callback The function to call after the animation finishes
1756 * @return {Roo.Element} this
1758 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1759 var action = function(){
1760 this.alignTo(el, alignment, offsets, animate);
1761 Roo.callback(callback, this);
1763 Roo.EventManager.onWindowResize(action, this);
1764 var tm = typeof monitorScroll;
1765 if(tm != 'undefined'){
1766 Roo.EventManager.on(window, 'scroll', action, this,
1767 {buffer: tm == 'number' ? monitorScroll : 50});
1769 action.call(this); // align immediately
1773 * Clears any opacity settings from this element. Required in some cases for IE.
1774 * @return {Roo.Element} this
1776 clearOpacity : function(){
1777 if (window.ActiveXObject) {
1778 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1779 this.dom.style.filter = "";
1782 this.dom.style.opacity = "";
1783 this.dom.style["-moz-opacity"] = "";
1784 this.dom.style["-khtml-opacity"] = "";
1790 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1791 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1792 * @return {Roo.Element} this
1794 hide : function(animate){
1795 this.setVisible(false, this.preanim(arguments, 0));
1800 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1801 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1802 * @return {Roo.Element} this
1804 show : function(animate){
1805 this.setVisible(true, this.preanim(arguments, 0));
1810 * @private Test if size has a unit, otherwise appends the default
1812 addUnits : function(size){
1813 return Roo.Element.addUnits(size, this.defaultUnit);
1817 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1818 * @return {Roo.Element} this
1820 beginMeasure : function(){
1822 if(el.offsetWidth || el.offsetHeight){
1823 return this; // offsets work already
1826 var p = this.dom, b = document.body; // start with this element
1827 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1828 var pe = Roo.get(p);
1829 if(pe.getStyle('display') == 'none'){
1830 changed.push({el: p, visibility: pe.getStyle("visibility")});
1831 p.style.visibility = "hidden";
1832 p.style.display = "block";
1836 this._measureChanged = changed;
1842 * Restores displays to before beginMeasure was called
1843 * @return {Roo.Element} this
1845 endMeasure : function(){
1846 var changed = this._measureChanged;
1848 for(var i = 0, len = changed.length; i < len; i++) {
1850 r.el.style.visibility = r.visibility;
1851 r.el.style.display = "none";
1853 this._measureChanged = null;
1859 * Update the innerHTML of this element, optionally searching for and processing scripts
1860 * @param {String} html The new HTML
1861 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1862 * @param {Function} callback For async script loading you can be noticed when the update completes
1863 * @return {Roo.Element} this
1865 update : function(html, loadScripts, callback){
1866 if(typeof html == "undefined"){
1869 if(loadScripts !== true){
1870 this.dom.innerHTML = html;
1871 if(typeof callback == "function"){
1879 html += '<span id="' + id + '"></span>';
1881 E.onAvailable(id, function(){
1882 var hd = document.getElementsByTagName("head")[0];
1883 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1884 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1885 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1888 while(match = re.exec(html)){
1889 var attrs = match[1];
1890 var srcMatch = attrs ? attrs.match(srcRe) : false;
1891 if(srcMatch && srcMatch[2]){
1892 var s = document.createElement("script");
1893 s.src = srcMatch[2];
1894 var typeMatch = attrs.match(typeRe);
1895 if(typeMatch && typeMatch[2]){
1896 s.type = typeMatch[2];
1899 }else if(match[2] && match[2].length > 0){
1900 if(window.execScript) {
1901 window.execScript(match[2]);
1909 window.eval(match[2]);
1913 var el = document.getElementById(id);
1914 if(el){el.parentNode.removeChild(el);}
1915 if(typeof callback == "function"){
1919 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1924 * Direct access to the UpdateManager update() method (takes the same parameters).
1925 * @param {String/Function} url The url for this request or a function to call to get the url
1926 * @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}
1927 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1928 * @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.
1929 * @return {Roo.Element} this
1932 var um = this.getUpdateManager();
1933 um.update.apply(um, arguments);
1938 * Gets this element's UpdateManager
1939 * @return {Roo.UpdateManager} The UpdateManager
1941 getUpdateManager : function(){
1942 if(!this.updateManager){
1943 this.updateManager = new Roo.UpdateManager(this);
1945 return this.updateManager;
1949 * Disables text selection for this element (normalized across browsers)
1950 * @return {Roo.Element} this
1952 unselectable : function(){
1953 this.dom.unselectable = "on";
1954 this.swallowEvent("selectstart", true);
1955 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1956 this.addClass("x-unselectable");
1961 * Calculates the x, y to center this element on the screen
1962 * @return {Array} The x, y values [x, y]
1964 getCenterXY : function(){
1965 return this.getAlignToXY(document, 'c-c');
1969 * Centers the Element in either the viewport, or another Element.
1970 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1972 center : function(centerIn){
1973 this.alignTo(centerIn || document, 'c-c');
1978 * Tests various css rules/browsers to determine if this element uses a border box
1981 isBorderBox : function(){
1982 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1986 * Return a box {x, y, width, height} that can be used to set another elements
1987 * size/location to match this element.
1988 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1989 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1990 * @return {Object} box An object in the format {x, y, width, height}
1992 getBox : function(contentBox, local){
1997 var left = parseInt(this.getStyle("left"), 10) || 0;
1998 var top = parseInt(this.getStyle("top"), 10) || 0;
2001 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
2003 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
2005 var l = this.getBorderWidth("l")+this.getPadding("l");
2006 var r = this.getBorderWidth("r")+this.getPadding("r");
2007 var t = this.getBorderWidth("t")+this.getPadding("t");
2008 var b = this.getBorderWidth("b")+this.getPadding("b");
2009 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)};
2011 bx.right = bx.x + bx.width;
2012 bx.bottom = bx.y + bx.height;
2017 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2018 for more information about the sides.
2019 * @param {String} sides
2022 getFrameWidth : function(sides, onlyContentBox){
2023 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2027 * 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.
2028 * @param {Object} box The box to fill {x, y, width, height}
2029 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2030 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2031 * @return {Roo.Element} this
2033 setBox : function(box, adjust, animate){
2034 var w = box.width, h = box.height;
2035 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2036 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2037 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2039 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2044 * Forces the browser to repaint this element
2045 * @return {Roo.Element} this
2047 repaint : function(){
2049 this.addClass("x-repaint");
2050 setTimeout(function(){
2051 Roo.get(dom).removeClass("x-repaint");
2057 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2058 * then it returns the calculated width of the sides (see getPadding)
2059 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2060 * @return {Object/Number}
2062 getMargins : function(side){
2065 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2066 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2067 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2068 right: parseInt(this.getStyle("margin-right"), 10) || 0
2071 return this.addStyles(side, El.margins);
2076 addStyles : function(sides, styles){
2078 for(var i = 0, len = sides.length; i < len; i++){
2079 v = this.getStyle(styles[sides.charAt(i)]);
2081 w = parseInt(v, 10);
2089 * Creates a proxy element of this element
2090 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2091 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2092 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2093 * @return {Roo.Element} The new proxy element
2095 createProxy : function(config, renderTo, matchBox){
2097 renderTo = Roo.getDom(renderTo);
2099 renderTo = document.body;
2101 config = typeof config == "object" ?
2102 config : {tag : "div", cls: config};
2103 var proxy = Roo.DomHelper.append(renderTo, config, true);
2105 proxy.setBox(this.getBox());
2111 * Puts a mask over this element to disable user interaction. Requires core.css.
2112 * This method can only be applied to elements which accept child nodes.
2113 * @param {String} msg (optional) A message to display in the mask
2114 * @param {String} msgCls (optional) A css class to apply to the msg element
2115 * @return {Element} The mask element
2117 mask : function(msg, msgCls)
2119 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2120 this.setStyle("position", "relative");
2123 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2125 this.addClass("x-masked");
2126 this._mask.setDisplayed(true);
2131 while (dom && dom.style) {
2132 if (!isNaN(parseInt(dom.style.zIndex))) {
2133 z = Math.max(z, parseInt(dom.style.zIndex));
2135 dom = dom.parentNode;
2137 // if we are masking the body - then it hides everything..
2138 if (this.dom == document.body) {
2140 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2141 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2144 if(typeof msg == 'string'){
2146 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2148 var mm = this._maskMsg;
2149 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2150 if (mm.dom.firstChild) { // weird IE issue?
2151 mm.dom.firstChild.innerHTML = msg;
2153 mm.setDisplayed(true);
2155 mm.setStyle('z-index', z + 102);
2157 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2158 this._mask.setHeight(this.getHeight());
2160 this._mask.setStyle('z-index', z + 100);
2166 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2167 * it is cached for reuse.
2169 unmask : function(removeEl){
2171 if(removeEl === true){
2172 this._mask.remove();
2175 this._maskMsg.remove();
2176 delete this._maskMsg;
2179 this._mask.setDisplayed(false);
2181 this._maskMsg.setDisplayed(false);
2185 this.removeClass("x-masked");
2189 * Returns true if this element is masked
2192 isMasked : function(){
2193 return this._mask && this._mask.isVisible();
2197 * Creates an iframe shim for this element to keep selects and other windowed objects from
2199 * @return {Roo.Element} The new shim element
2201 createShim : function(){
2202 var el = document.createElement('iframe');
2203 el.frameBorder = 'no';
2204 el.className = 'roo-shim';
2205 if(Roo.isIE && Roo.isSecure){
2206 el.src = Roo.SSL_SECURE_URL;
2208 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2209 shim.autoBoxAdjust = false;
2214 * Removes this element from the DOM and deletes it from the cache
2216 remove : function(){
2217 if(this.dom.parentNode){
2218 this.dom.parentNode.removeChild(this.dom);
2220 delete El.cache[this.dom.id];
2224 * Sets up event handlers to add and remove a css class when the mouse is over this element
2225 * @param {String} className
2226 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2227 * mouseout events for children elements
2228 * @return {Roo.Element} this
2230 addClassOnOver : function(className, preventFlicker){
2231 this.on("mouseover", function(){
2232 Roo.fly(this, '_internal').addClass(className);
2234 var removeFn = function(e){
2235 if(preventFlicker !== true || !e.within(this, true)){
2236 Roo.fly(this, '_internal').removeClass(className);
2239 this.on("mouseout", removeFn, this.dom);
2244 * Sets up event handlers to add and remove a css class when this element has the focus
2245 * @param {String} className
2246 * @return {Roo.Element} this
2248 addClassOnFocus : function(className){
2249 this.on("focus", function(){
2250 Roo.fly(this, '_internal').addClass(className);
2252 this.on("blur", function(){
2253 Roo.fly(this, '_internal').removeClass(className);
2258 * 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)
2259 * @param {String} className
2260 * @return {Roo.Element} this
2262 addClassOnClick : function(className){
2264 this.on("mousedown", function(){
2265 Roo.fly(dom, '_internal').addClass(className);
2266 var d = Roo.get(document);
2267 var fn = function(){
2268 Roo.fly(dom, '_internal').removeClass(className);
2269 d.removeListener("mouseup", fn);
2271 d.on("mouseup", fn);
2277 * Stops the specified event from bubbling and optionally prevents the default action
2278 * @param {String} eventName
2279 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2280 * @return {Roo.Element} this
2282 swallowEvent : function(eventName, preventDefault){
2283 var fn = function(e){
2284 e.stopPropagation();
2289 if(eventName instanceof Array){
2290 for(var i = 0, len = eventName.length; i < len; i++){
2291 this.on(eventName[i], fn);
2295 this.on(eventName, fn);
2302 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2305 * Sizes this element to its parent element's dimensions performing
2306 * neccessary box adjustments.
2307 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2308 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2309 * @return {Roo.Element} this
2311 fitToParent : function(monitorResize, targetParent) {
2312 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2313 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2314 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2317 var p = Roo.get(targetParent || this.dom.parentNode);
2318 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2319 if (monitorResize === true) {
2320 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2321 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2327 * Gets the next sibling, skipping text nodes
2328 * @return {HTMLElement} The next sibling or null
2330 getNextSibling : function(){
2331 var n = this.dom.nextSibling;
2332 while(n && n.nodeType != 1){
2339 * Gets the previous sibling, skipping text nodes
2340 * @return {HTMLElement} The previous sibling or null
2342 getPrevSibling : function(){
2343 var n = this.dom.previousSibling;
2344 while(n && n.nodeType != 1){
2345 n = n.previousSibling;
2352 * Appends the passed element(s) to this element
2353 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2354 * @return {Roo.Element} this
2356 appendChild: function(el){
2363 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2364 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2365 * automatically generated with the specified attributes.
2366 * @param {HTMLElement} insertBefore (optional) a child element of this element
2367 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2368 * @return {Roo.Element} The new child element
2370 createChild: function(config, insertBefore, returnDom){
2371 config = config || {tag:'div'};
2373 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2375 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2379 * Appends this element to the passed element
2380 * @param {String/HTMLElement/Element} el The new parent element
2381 * @return {Roo.Element} this
2383 appendTo: function(el){
2384 el = Roo.getDom(el);
2385 el.appendChild(this.dom);
2390 * Inserts this element before the passed element in the DOM
2391 * @param {String/HTMLElement/Element} el The element to insert before
2392 * @return {Roo.Element} this
2394 insertBefore: function(el){
2395 el = Roo.getDom(el);
2396 el.parentNode.insertBefore(this.dom, el);
2401 * Inserts this element after the passed element in the DOM
2402 * @param {String/HTMLElement/Element} el The element to insert after
2403 * @return {Roo.Element} this
2405 insertAfter: function(el){
2406 el = Roo.getDom(el);
2407 el.parentNode.insertBefore(this.dom, el.nextSibling);
2412 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2413 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2414 * @return {Roo.Element} The new child
2416 insertFirst: function(el, returnDom){
2418 if(typeof el == 'object' && !el.nodeType){ // dh config
2419 return this.createChild(el, this.dom.firstChild, returnDom);
2421 el = Roo.getDom(el);
2422 this.dom.insertBefore(el, this.dom.firstChild);
2423 return !returnDom ? Roo.get(el) : el;
2428 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2429 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2430 * @param {String} where (optional) 'before' or 'after' defaults to before
2431 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2432 * @return {Roo.Element} the inserted Element
2434 insertSibling: function(el, where, returnDom){
2435 where = where ? where.toLowerCase() : 'before';
2437 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2439 if(typeof el == 'object' && !el.nodeType){ // dh config
2440 if(where == 'after' && !this.dom.nextSibling){
2441 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2443 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2447 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2448 where == 'before' ? this.dom : this.dom.nextSibling);
2457 * Creates and wraps this element with another element
2458 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2459 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2460 * @return {HTMLElement/Element} The newly created wrapper element
2462 wrap: function(config, returnDom){
2464 config = {tag: "div"};
2466 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2467 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2472 * Replaces the passed element with this element
2473 * @param {String/HTMLElement/Element} el The element to replace
2474 * @return {Roo.Element} this
2476 replace: function(el){
2478 this.insertBefore(el);
2484 * Inserts an html fragment into this element
2485 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2486 * @param {String} html The HTML fragment
2487 * @param {Boolean} returnEl True to return an Roo.Element
2488 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2490 insertHtml : function(where, html, returnEl){
2491 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2492 return returnEl ? Roo.get(el) : el;
2496 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2497 * @param {Object} o The object with the attributes
2498 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2499 * @return {Roo.Element} this
2501 set : function(o, useSet){
2503 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2505 if(attr == "style" || typeof o[attr] == "function") { continue; }
2507 el.className = o["cls"];
2510 el.setAttribute(attr, o[attr]);
2517 Roo.DomHelper.applyStyles(el, o.style);
2523 * Convenience method for constructing a KeyMap
2524 * @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:
2525 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2526 * @param {Function} fn The function to call
2527 * @param {Object} scope (optional) The scope of the function
2528 * @return {Roo.KeyMap} The KeyMap created
2530 addKeyListener : function(key, fn, scope){
2532 if(typeof key != "object" || key instanceof Array){
2548 return new Roo.KeyMap(this, config);
2552 * Creates a KeyMap for this element
2553 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2554 * @return {Roo.KeyMap} The KeyMap created
2556 addKeyMap : function(config){
2557 return new Roo.KeyMap(this, config);
2561 * Returns true if this element is scrollable.
2564 isScrollable : function(){
2566 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2570 * 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().
2571 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2572 * @param {Number} value The new scroll value
2573 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2574 * @return {Element} this
2577 scrollTo : function(side, value, animate){
2578 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2580 this.dom[prop] = value;
2582 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2583 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2589 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2590 * within this element's scrollable range.
2591 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2592 * @param {Number} distance How far to scroll the element in pixels
2593 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2594 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2595 * was scrolled as far as it could go.
2597 scroll : function(direction, distance, animate){
2598 if(!this.isScrollable()){
2602 var l = el.scrollLeft, t = el.scrollTop;
2603 var w = el.scrollWidth, h = el.scrollHeight;
2604 var cw = el.clientWidth, ch = el.clientHeight;
2605 direction = direction.toLowerCase();
2606 var scrolled = false;
2607 var a = this.preanim(arguments, 2);
2612 var v = Math.min(l + distance, w-cw);
2613 this.scrollTo("left", v, a);
2620 var v = Math.max(l - distance, 0);
2621 this.scrollTo("left", v, a);
2629 var v = Math.max(t - distance, 0);
2630 this.scrollTo("top", v, a);
2638 var v = Math.min(t + distance, h-ch);
2639 this.scrollTo("top", v, a);
2648 * Translates the passed page coordinates into left/top css values for this element
2649 * @param {Number/Array} x The page x or an array containing [x, y]
2650 * @param {Number} y The page y
2651 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2653 translatePoints : function(x, y){
2654 if(typeof x == 'object' || x instanceof Array){
2657 var p = this.getStyle('position');
2658 var o = this.getXY();
2660 var l = parseInt(this.getStyle('left'), 10);
2661 var t = parseInt(this.getStyle('top'), 10);
2664 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2667 t = (p == "relative") ? 0 : this.dom.offsetTop;
2670 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2674 * Returns the current scroll position of the element.
2675 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2677 getScroll : function(){
2678 var d = this.dom, doc = document;
2679 if(d == doc || d == doc.body){
2680 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2681 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2682 return {left: l, top: t};
2684 return {left: d.scrollLeft, top: d.scrollTop};
2689 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2690 * are convert to standard 6 digit hex color.
2691 * @param {String} attr The css attribute
2692 * @param {String} defaultValue The default value to use when a valid color isn't found
2693 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2696 getColor : function(attr, defaultValue, prefix){
2697 var v = this.getStyle(attr);
2698 if(!v || v == "transparent" || v == "inherit") {
2699 return defaultValue;
2701 var color = typeof prefix == "undefined" ? "#" : prefix;
2702 if(v.substr(0, 4) == "rgb("){
2703 var rvs = v.slice(4, v.length -1).split(",");
2704 for(var i = 0; i < 3; i++){
2705 var h = parseInt(rvs[i]).toString(16);
2712 if(v.substr(0, 1) == "#"){
2714 for(var i = 1; i < 4; i++){
2715 var c = v.charAt(i);
2718 }else if(v.length == 7){
2719 color += v.substr(1);
2723 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2727 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2728 * gradient background, rounded corners and a 4-way shadow.
2729 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2730 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2731 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2732 * @return {Roo.Element} this
2734 boxWrap : function(cls){
2735 cls = cls || 'x-box';
2736 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2737 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2742 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2743 * @param {String} namespace The namespace in which to look for the attribute
2744 * @param {String} name The attribute name
2745 * @return {String} The attribute value
2747 getAttributeNS : Roo.isIE ? function(ns, name){
2749 var type = typeof d[ns+":"+name];
2750 if(type != 'undefined' && type != 'unknown'){
2751 return d[ns+":"+name];
2754 } : function(ns, name){
2756 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2761 * Sets or Returns the value the dom attribute value
2762 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2763 * @param {String} value (optional) The value to set the attribute to
2764 * @return {String} The attribute value
2766 attr : function(name){
2767 if (arguments.length > 1) {
2768 this.dom.setAttribute(name, arguments[1]);
2769 return arguments[1];
2771 if (typeof(name) == 'object') {
2772 for(var i in name) {
2773 this.attr(i, name[i]);
2779 if (!this.dom.hasAttribute(name)) {
2782 return this.dom.getAttribute(name);
2789 var ep = El.prototype;
2792 * Appends an event handler (Shorthand for addListener)
2793 * @param {String} eventName The type of event to append
2794 * @param {Function} fn The method the event invokes
2795 * @param {Object} scope (optional) The scope (this object) of the fn
2796 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2799 ep.on = ep.addListener;
2801 ep.mon = ep.addListener;
2804 * Removes an event handler from this element (shorthand for removeListener)
2805 * @param {String} eventName the type of event to remove
2806 * @param {Function} fn the method the event invokes
2807 * @return {Roo.Element} this
2810 ep.un = ep.removeListener;
2813 * true to automatically adjust width and height settings for box-model issues (default to true)
2815 ep.autoBoxAdjust = true;
2818 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2821 El.addUnits = function(v, defaultUnit){
2822 if(v === "" || v == "auto"){
2825 if(v === undefined){
2828 if(typeof v == "number" || !El.unitPattern.test(v)){
2829 return v + (defaultUnit || 'px');
2834 // special markup used throughout Roo when box wrapping elements
2835 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>';
2837 * Visibility mode constant - Use visibility to hide element
2843 * Visibility mode constant - Use display to hide element
2849 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2850 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2851 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2863 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2864 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2865 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2866 * @return {Element} The Element object
2869 El.get = function(el){
2871 if(!el){ return null; }
2872 if(typeof el == "string"){ // element id
2873 if(!(elm = document.getElementById(el))){
2876 if(ex = El.cache[el]){
2879 ex = El.cache[el] = new El(elm);
2882 }else if(el.tagName){ // dom element
2886 if(ex = El.cache[id]){
2889 ex = El.cache[id] = new El(el);
2892 }else if(el instanceof El){
2894 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2895 // catch case where it hasn't been appended
2896 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2899 }else if(el.isComposite){
2901 }else if(el instanceof Array){
2902 return El.select(el);
2903 }else if(el == document){
2904 // create a bogus element object representing the document object
2906 var f = function(){};
2907 f.prototype = El.prototype;
2909 docEl.dom = document;
2917 El.uncache = function(el){
2918 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2920 delete El.cache[a[i].id || a[i]];
2926 // Garbage collection - uncache elements/purge listeners on orphaned elements
2927 // so we don't hold a reference and cause the browser to retain them
2928 El.garbageCollect = function(){
2929 if(!Roo.enableGarbageCollector){
2930 clearInterval(El.collectorThread);
2933 for(var eid in El.cache){
2934 var el = El.cache[eid], d = el.dom;
2935 // -------------------------------------------------------
2936 // Determining what is garbage:
2937 // -------------------------------------------------------
2939 // dom node is null, definitely garbage
2940 // -------------------------------------------------------
2942 // no parentNode == direct orphan, definitely garbage
2943 // -------------------------------------------------------
2944 // !d.offsetParent && !document.getElementById(eid)
2945 // display none elements have no offsetParent so we will
2946 // also try to look it up by it's id. However, check
2947 // offsetParent first so we don't do unneeded lookups.
2948 // This enables collection of elements that are not orphans
2949 // directly, but somewhere up the line they have an orphan
2951 // -------------------------------------------------------
2952 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2953 delete El.cache[eid];
2954 if(d && Roo.enableListenerCollection){
2960 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2964 El.Flyweight = function(dom){
2967 El.Flyweight.prototype = El.prototype;
2969 El._flyweights = {};
2971 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2972 * the dom node can be overwritten by other code.
2973 * @param {String/HTMLElement} el The dom node or id
2974 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2975 * prevent conflicts (e.g. internally Roo uses "_internal")
2977 * @return {Element} The shared Element object
2979 El.fly = function(el, named){
2980 named = named || '_global';
2981 el = Roo.getDom(el);
2985 if(!El._flyweights[named]){
2986 El._flyweights[named] = new El.Flyweight();
2988 El._flyweights[named].dom = el;
2989 return El._flyweights[named];
2993 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2994 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2995 * Shorthand of {@link Roo.Element#get}
2996 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2997 * @return {Element} The Element object
3003 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3004 * the dom node can be overwritten by other code.
3005 * Shorthand of {@link Roo.Element#fly}
3006 * @param {String/HTMLElement} el The dom node or id
3007 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3008 * prevent conflicts (e.g. internally Roo uses "_internal")
3010 * @return {Element} The shared Element object
3016 // speedy lookup for elements never to box adjust
3017 var noBoxAdjust = Roo.isStrict ? {
3020 input:1, select:1, textarea:1
3022 if(Roo.isIE || Roo.isGecko){
3023 noBoxAdjust['button'] = 1;
3027 Roo.EventManager.on(window, 'unload', function(){
3029 delete El._flyweights;
3037 Roo.Element.selectorFunction = Roo.DomQuery.select;
3040 Roo.Element.select = function(selector, unique, root){
3042 if(typeof selector == "string"){
3043 els = Roo.Element.selectorFunction(selector, root);
3044 }else if(selector.length !== undefined){
3047 throw "Invalid selector";
3049 if(unique === true){
3050 return new Roo.CompositeElement(els);
3052 return new Roo.CompositeElementLite(els);
3056 * Selects elements based on the passed CSS selector to enable working on them as 1.
3057 * @param {String/Array} selector The CSS selector or an array of elements
3058 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3059 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3060 * @return {CompositeElementLite/CompositeElement}
3064 Roo.select = Roo.Element.select;