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);
197 !el.isScrollable() &&
198 D.getViewHeight() - el.dom.clientHeight <= 15 &&
199 D.getViewWidth() - el.dom.clientWidth <= 15 &&
200 el.dom.nodeName.toLowerCase() != 'body'
202 el = Roo.get(el.dom.parentNode);
205 if(!el.isScrollable()){
213 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
214 * This is a shortcut for findParentNode() that always returns an Roo.Element.
215 * @param {String} selector The simple selector to test
216 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
217 search as a number or element (defaults to 10 || document.body)
218 * @return {Roo.Element} The matching DOM node (or null if no match was found)
220 up : function(simpleSelector, maxDepth){
221 return this.findParentNode(simpleSelector, maxDepth, true);
227 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
228 * @param {String} selector The simple selector to test
229 * @return {Boolean} True if this element matches the selector, else false
231 is : function(simpleSelector){
232 return Roo.DomQuery.is(this.dom, simpleSelector);
236 * Perform animation on this element.
237 * @param {Object} args The YUI animation control args
238 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
239 * @param {Function} onComplete (optional) Function to call when animation completes
240 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
241 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
242 * @return {Roo.Element} this
244 animate : function(args, duration, onComplete, easing, animType){
245 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
250 * @private Internal animation call
252 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
253 animType = animType || 'run';
255 var anim = Roo.lib.Anim[animType](
257 (opt.duration || defaultDur) || .35,
258 (opt.easing || defaultEase) || 'easeOut',
260 Roo.callback(cb, this);
261 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
269 // private legacy anim prep
270 preanim : function(a, i){
271 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
275 * Removes worthless text nodes
276 * @param {Boolean} forceReclean (optional) By default the element
277 * keeps track if it has been cleaned already so
278 * you can call this over and over. However, if you update the element and
279 * need to force a reclean, you can pass true.
281 clean : function(forceReclean){
282 if(this.isCleaned && forceReclean !== true){
286 var d = this.dom, n = d.firstChild, ni = -1;
288 var nx = n.nextSibling;
289 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
296 this.isCleaned = true;
301 calcOffsetsTo : function(el){
304 var restorePos = false;
305 if(el.getStyle('position') == 'static'){
306 el.position('relative');
311 while(op && op != d && op.tagName != 'HTML'){
314 op = op.offsetParent;
317 el.position('static');
323 * Scrolls this element into view within the passed container.
324 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
325 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
326 * @return {Roo.Element} this
328 scrollIntoView : function(container, hscroll){
329 var c = Roo.getDom(container) || document.body;
332 var o = this.calcOffsetsTo(c),
335 b = t+el.offsetHeight,
336 r = l+el.offsetWidth;
338 var ch = c.clientHeight;
339 var ct = parseInt(c.scrollTop, 10);
340 var cl = parseInt(c.scrollLeft, 10);
342 var cr = cl + c.clientWidth;
350 if(hscroll !== false){
354 c.scrollLeft = r-c.clientWidth;
361 scrollChildIntoView : function(child, hscroll){
362 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
366 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
367 * the new height may not be available immediately.
368 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
369 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
370 * @param {Function} onComplete (optional) Function to call when animation completes
371 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
372 * @return {Roo.Element} this
374 autoHeight : function(animate, duration, onComplete, easing){
375 var oldHeight = this.getHeight();
377 this.setHeight(1); // force clipping
378 setTimeout(function(){
379 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
381 this.setHeight(height);
383 if(typeof onComplete == "function"){
387 this.setHeight(oldHeight); // restore original height
388 this.setHeight(height, animate, duration, function(){
390 if(typeof onComplete == "function") { onComplete(); }
391 }.createDelegate(this), easing);
393 }.createDelegate(this), 0);
398 * Returns true if this element is an ancestor of the passed element
399 * @param {HTMLElement/String} el The element to check
400 * @return {Boolean} True if this element is an ancestor of el, else false
402 contains : function(el){
403 if(!el){return false;}
404 return D.isAncestor(this.dom, el.dom ? el.dom : el);
408 * Checks whether the element is currently visible using both visibility and display properties.
409 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
410 * @return {Boolean} True if the element is currently visible, else false
412 isVisible : function(deep) {
413 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
414 if(deep !== true || !vis){
417 var p = this.dom.parentNode;
418 while(p && p.tagName.toLowerCase() != "body"){
419 if(!Roo.fly(p, '_isVisible').isVisible()){
428 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
429 * @param {String} selector The CSS selector
430 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
431 * @return {CompositeElement/CompositeElementLite} The composite element
433 select : function(selector, unique){
434 return El.select(selector, unique, this.dom);
438 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
439 * @param {String} selector The CSS selector
440 * @return {Array} An array of the matched nodes
442 query : function(selector, unique){
443 return Roo.DomQuery.select(selector, this.dom);
447 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
448 * @param {String} selector The CSS selector
449 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
450 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
452 child : function(selector, returnDom){
453 var n = Roo.DomQuery.selectNode(selector, this.dom);
454 return returnDom ? n : Roo.get(n);
458 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
459 * @param {String} selector The CSS selector
460 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
461 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
463 down : function(selector, returnDom){
464 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
465 return returnDom ? n : Roo.get(n);
469 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
470 * @param {String} group The group the DD object is member of
471 * @param {Object} config The DD config object
472 * @param {Object} overrides An object containing methods to override/implement on the DD object
473 * @return {Roo.dd.DD} The DD object
475 initDD : function(group, config, overrides){
476 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
477 return Roo.apply(dd, overrides);
481 * Initializes a {@link Roo.dd.DDProxy} object for this element.
482 * @param {String} group The group the DDProxy object is member of
483 * @param {Object} config The DDProxy config object
484 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
485 * @return {Roo.dd.DDProxy} The DDProxy object
487 initDDProxy : function(group, config, overrides){
488 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
489 return Roo.apply(dd, overrides);
493 * Initializes a {@link Roo.dd.DDTarget} object for this element.
494 * @param {String} group The group the DDTarget object is member of
495 * @param {Object} config The DDTarget config object
496 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
497 * @return {Roo.dd.DDTarget} The DDTarget object
499 initDDTarget : function(group, config, overrides){
500 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
501 return Roo.apply(dd, overrides);
505 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
506 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
507 * @param {Boolean} visible Whether the element is visible
508 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
509 * @return {Roo.Element} this
511 setVisible : function(visible, animate){
513 if(this.visibilityMode == El.DISPLAY){
514 this.setDisplayed(visible);
517 this.dom.style.visibility = visible ? "visible" : "hidden";
520 // closure for composites
522 var visMode = this.visibilityMode;
524 this.setOpacity(.01);
525 this.setVisible(true);
527 this.anim({opacity: { to: (visible?1:0) }},
528 this.preanim(arguments, 1),
529 null, .35, 'easeIn', function(){
531 if(visMode == El.DISPLAY){
532 dom.style.display = "none";
534 dom.style.visibility = "hidden";
536 Roo.get(dom).setOpacity(1);
544 * Returns true if display is not "none"
547 isDisplayed : function() {
548 return this.getStyle("display") != "none";
552 * Toggles the element's visibility or display, depending on visibility mode.
553 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
554 * @return {Roo.Element} this
556 toggle : function(animate){
557 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
562 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
563 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
564 * @return {Roo.Element} this
566 setDisplayed : function(value) {
567 if(typeof value == "boolean"){
568 value = value ? this.originalDisplay : "none";
570 this.setStyle("display", value);
575 * Tries to focus the element. Any exceptions are caught and ignored.
576 * @return {Roo.Element} this
586 * Tries to blur the element. Any exceptions are caught and ignored.
587 * @return {Roo.Element} this
597 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
598 * @param {String/Array} className The CSS class to add, or an array of classes
599 * @return {Roo.Element} this
601 addClass : function(className){
602 if(className instanceof Array){
603 for(var i = 0, len = className.length; i < len; i++) {
604 this.addClass(className[i]);
607 if(className && !this.hasClass(className)){
608 this.dom.className = this.dom.className + " " + className;
615 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
616 * @param {String/Array} className The CSS class to add, or an array of classes
617 * @return {Roo.Element} this
619 radioClass : function(className){
620 var siblings = this.dom.parentNode.childNodes;
621 for(var i = 0; i < siblings.length; i++) {
624 Roo.get(s).removeClass(className);
627 this.addClass(className);
632 * Removes one or more CSS classes from the element.
633 * @param {String/Array} className The CSS class to remove, or an array of classes
634 * @return {Roo.Element} this
636 removeClass : function(className){
637 if(!className || !this.dom.className){
640 if(className instanceof Array){
641 for(var i = 0, len = className.length; i < len; i++) {
642 this.removeClass(className[i]);
645 if(this.hasClass(className)){
646 var re = this.classReCache[className];
648 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
649 this.classReCache[className] = re;
652 this.dom.className.replace(re, " ");
662 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
663 * @param {String} className The CSS class to toggle
664 * @return {Roo.Element} this
666 toggleClass : function(className){
667 if(this.hasClass(className)){
668 this.removeClass(className);
670 this.addClass(className);
676 * Checks if the specified CSS class exists on this element's DOM node.
677 * @param {String} className The CSS class to check for
678 * @return {Boolean} True if the class exists, else false
680 hasClass : function(className){
681 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
685 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
686 * @param {String} oldClassName The CSS class to replace
687 * @param {String} newClassName The replacement CSS class
688 * @return {Roo.Element} this
690 replaceClass : function(oldClassName, newClassName){
691 this.removeClass(oldClassName);
692 this.addClass(newClassName);
697 * Returns an object with properties matching the styles requested.
698 * For example, el.getStyles('color', 'font-size', 'width') might return
699 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
700 * @param {String} style1 A style name
701 * @param {String} style2 A style name
702 * @param {String} etc.
703 * @return {Object} The style object
705 getStyles : function(){
706 var a = arguments, len = a.length, r = {};
707 for(var i = 0; i < len; i++){
708 r[a[i]] = this.getStyle(a[i]);
714 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
715 * @param {String} property The style property whose value is returned.
716 * @return {String} The current value of the style property for this element.
718 getStyle : function(){
719 return view && view.getComputedStyle ?
721 var el = this.dom, v, cs, camel;
725 if(el.style && (v = el.style[prop])){
728 if(cs = view.getComputedStyle(el, "")){
729 if(!(camel = propCache[prop])){
730 camel = propCache[prop] = prop.replace(camelRe, camelFn);
737 var el = this.dom, v, cs, camel;
738 if(prop == 'opacity'){
739 if(typeof el.style.filter == 'string'){
740 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
742 var fv = parseFloat(m[1]);
744 return fv ? fv / 100 : 0;
749 }else if(prop == 'float'){
752 if(!(camel = propCache[prop])){
753 camel = propCache[prop] = prop.replace(camelRe, camelFn);
755 if(v = el.style[camel]){
758 if(cs = el.currentStyle){
766 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
767 * @param {String/Object} property The style property to be set, or an object of multiple styles.
768 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
769 * @return {Roo.Element} this
771 setStyle : function(prop, value){
772 if(typeof prop == "string"){
774 if (prop == 'float') {
775 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
780 if(!(camel = propCache[prop])){
781 camel = propCache[prop] = prop.replace(camelRe, camelFn);
784 if(camel == 'opacity') {
785 this.setOpacity(value);
787 this.dom.style[camel] = value;
790 for(var style in prop){
791 if(typeof prop[style] != "function"){
792 this.setStyle(style, prop[style]);
800 * More flexible version of {@link #setStyle} for setting style properties.
801 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
802 * a function which returns such a specification.
803 * @return {Roo.Element} this
805 applyStyles : function(style){
806 Roo.DomHelper.applyStyles(this.dom, style);
811 * 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).
812 * @return {Number} The X position of the element
815 return D.getX(this.dom);
819 * 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).
820 * @return {Number} The Y position of the element
823 return D.getY(this.dom);
827 * 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).
828 * @return {Array} The XY position of the element
831 return D.getXY(this.dom);
835 * 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).
836 * @param {Number} The X position of the element
837 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
838 * @return {Roo.Element} this
840 setX : function(x, animate){
844 this.setXY([x, this.getY()], this.preanim(arguments, 1));
850 * 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).
851 * @param {Number} The Y position of the element
852 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
853 * @return {Roo.Element} this
855 setY : function(y, animate){
859 this.setXY([this.getX(), y], this.preanim(arguments, 1));
865 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
866 * @param {String} left The left CSS property value
867 * @return {Roo.Element} this
869 setLeft : function(left){
870 this.setStyle("left", this.addUnits(left));
875 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
876 * @param {String} top The top CSS property value
877 * @return {Roo.Element} this
879 setTop : function(top){
880 this.setStyle("top", this.addUnits(top));
885 * Sets the element's CSS right style.
886 * @param {String} right The right CSS property value
887 * @return {Roo.Element} this
889 setRight : function(right){
890 this.setStyle("right", this.addUnits(right));
895 * Sets the element's CSS bottom style.
896 * @param {String} bottom The bottom CSS property value
897 * @return {Roo.Element} this
899 setBottom : function(bottom){
900 this.setStyle("bottom", this.addUnits(bottom));
905 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
906 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
907 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
908 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
909 * @return {Roo.Element} this
911 setXY : function(pos, animate){
913 D.setXY(this.dom, pos);
915 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
921 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
922 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
923 * @param {Number} x X value for new position (coordinates are page-based)
924 * @param {Number} y Y value 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 setLocation : function(x, y, animate){
929 this.setXY([x, y], this.preanim(arguments, 2));
934 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
935 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
936 * @param {Number} x X value for new position (coordinates are page-based)
937 * @param {Number} y Y value for new position (coordinates are page-based)
938 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
939 * @return {Roo.Element} this
941 moveTo : function(x, y, animate){
942 this.setXY([x, y], this.preanim(arguments, 2));
947 * Returns the region of the given element.
948 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
949 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
951 getRegion : function(){
952 return D.getRegion(this.dom);
956 * Returns the offset height of the element
957 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
958 * @return {Number} The element's height
960 getHeight : function(contentHeight){
961 var h = this.dom.offsetHeight || 0;
962 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
966 * Returns the offset width of the element
967 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
968 * @return {Number} The element's width
970 getWidth : function(contentWidth){
971 var w = this.dom.offsetWidth || 0;
972 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
976 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
977 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
978 * if a height has not been set using CSS.
981 getComputedHeight : function(){
982 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
984 h = parseInt(this.getStyle('height'), 10) || 0;
985 if(!this.isBorderBox()){
986 h += this.getFrameWidth('tb');
993 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
994 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
995 * if a width has not been set using CSS.
998 getComputedWidth : function(){
999 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1001 w = parseInt(this.getStyle('width'), 10) || 0;
1002 if(!this.isBorderBox()){
1003 w += this.getFrameWidth('lr');
1010 * Returns the size of the element.
1011 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1012 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1014 getSize : function(contentSize){
1015 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1019 * Returns the width and height of the viewport.
1020 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1022 getViewSize : function(){
1023 var d = this.dom, doc = document, aw = 0, ah = 0;
1024 if(d == doc || d == doc.body){
1025 return {width : D.getViewWidth(), height: D.getViewHeight()};
1028 width : d.clientWidth,
1029 height: d.clientHeight
1035 * Returns the value of the "value" attribute
1036 * @param {Boolean} asNumber true to parse the value as a number
1037 * @return {String/Number}
1039 getValue : function(asNumber){
1040 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1044 adjustWidth : function(width){
1045 if(typeof width == "number"){
1046 if(this.autoBoxAdjust && !this.isBorderBox()){
1047 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1057 adjustHeight : function(height){
1058 if(typeof height == "number"){
1059 if(this.autoBoxAdjust && !this.isBorderBox()){
1060 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1070 * Set the width of the element
1071 * @param {Number} width The new width
1072 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1073 * @return {Roo.Element} this
1075 setWidth : function(width, animate){
1076 width = this.adjustWidth(width);
1078 this.dom.style.width = this.addUnits(width);
1080 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1086 * Set the height of the element
1087 * @param {Number} height The new height
1088 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1089 * @return {Roo.Element} this
1091 setHeight : function(height, animate){
1092 height = this.adjustHeight(height);
1094 this.dom.style.height = this.addUnits(height);
1096 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1102 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1103 * @param {Number} width The new width
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 setSize : function(width, height, animate){
1109 if(typeof width == "object"){ // in case of object from getSize()
1110 height = width.height; width = width.width;
1112 width = this.adjustWidth(width); height = this.adjustHeight(height);
1114 this.dom.style.width = this.addUnits(width);
1115 this.dom.style.height = this.addUnits(height);
1117 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1123 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1124 * @param {Number} x X value for new position (coordinates are page-based)
1125 * @param {Number} y Y value for new position (coordinates are page-based)
1126 * @param {Number} width The new width
1127 * @param {Number} height The new height
1128 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1129 * @return {Roo.Element} this
1131 setBounds : function(x, y, width, height, animate){
1133 this.setSize(width, height);
1134 this.setLocation(x, y);
1136 width = this.adjustWidth(width); height = this.adjustHeight(height);
1137 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1138 this.preanim(arguments, 4), 'motion');
1144 * 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.
1145 * @param {Roo.lib.Region} region The region to fill
1146 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1147 * @return {Roo.Element} this
1149 setRegion : function(region, animate){
1150 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1155 * Appends an event handler
1157 * @param {String} eventName The type of event to append
1158 * @param {Function} fn The method the event invokes
1159 * @param {Object} scope (optional) The scope (this object) of the fn
1160 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1162 addListener : function(eventName, fn, scope, options){
1164 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1169 * Removes an event handler from this element
1170 * @param {String} eventName the type of event to remove
1171 * @param {Function} fn the method the event invokes
1172 * @return {Roo.Element} this
1174 removeListener : function(eventName, fn){
1175 Roo.EventManager.removeListener(this.dom, eventName, fn);
1180 * Removes all previous added listeners from this element
1181 * @return {Roo.Element} this
1183 removeAllListeners : function(){
1184 E.purgeElement(this.dom);
1188 relayEvent : function(eventName, observable){
1189 this.on(eventName, function(e){
1190 observable.fireEvent(eventName, e);
1195 * Set the opacity of the element
1196 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1197 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1198 * @return {Roo.Element} this
1200 setOpacity : function(opacity, animate){
1202 var s = this.dom.style;
1205 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1206 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1208 s.opacity = opacity;
1211 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1217 * Gets the left X coordinate
1218 * @param {Boolean} local True to get the local css position instead of page coordinate
1221 getLeft : function(local){
1225 return parseInt(this.getStyle("left"), 10) || 0;
1230 * Gets the right X coordinate of the element (element X position + element width)
1231 * @param {Boolean} local True to get the local css position instead of page coordinate
1234 getRight : function(local){
1236 return this.getX() + this.getWidth();
1238 return (this.getLeft(true) + this.getWidth()) || 0;
1243 * Gets the top Y coordinate
1244 * @param {Boolean} local True to get the local css position instead of page coordinate
1247 getTop : function(local) {
1251 return parseInt(this.getStyle("top"), 10) || 0;
1256 * Gets the bottom Y coordinate of the element (element Y position + element height)
1257 * @param {Boolean} local True to get the local css position instead of page coordinate
1260 getBottom : function(local){
1262 return this.getY() + this.getHeight();
1264 return (this.getTop(true) + this.getHeight()) || 0;
1269 * Initializes positioning on this element. If a desired position is not passed, it will make the
1270 * the element positioned relative IF it is not already positioned.
1271 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1272 * @param {Number} zIndex (optional) The zIndex to apply
1273 * @param {Number} x (optional) Set the page X position
1274 * @param {Number} y (optional) Set the page Y position
1276 position : function(pos, zIndex, x, y){
1278 if(this.getStyle('position') == 'static'){
1279 this.setStyle('position', 'relative');
1282 this.setStyle("position", pos);
1285 this.setStyle("z-index", zIndex);
1287 if(x !== undefined && y !== undefined){
1289 }else if(x !== undefined){
1291 }else if(y !== undefined){
1297 * Clear positioning back to the default when the document was loaded
1298 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1299 * @return {Roo.Element} this
1301 clearPositioning : function(value){
1309 "position" : "static"
1315 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1316 * snapshot before performing an update and then restoring the element.
1319 getPositioning : function(){
1320 var l = this.getStyle("left");
1321 var t = this.getStyle("top");
1323 "position" : this.getStyle("position"),
1325 "right" : l ? "" : this.getStyle("right"),
1327 "bottom" : t ? "" : this.getStyle("bottom"),
1328 "z-index" : this.getStyle("z-index")
1333 * Gets the width of the border(s) for the specified side(s)
1334 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1335 * passing lr would get the border (l)eft width + the border (r)ight width.
1336 * @return {Number} The width of the sides passed added together
1338 getBorderWidth : function(side){
1339 return this.addStyles(side, El.borders);
1343 * Gets the width of the padding(s) for the specified side(s)
1344 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1345 * passing lr would get the padding (l)eft + the padding (r)ight.
1346 * @return {Number} The padding of the sides passed added together
1348 getPadding : function(side){
1349 return this.addStyles(side, El.paddings);
1353 * Set positioning with an object returned by getPositioning().
1354 * @param {Object} posCfg
1355 * @return {Roo.Element} this
1357 setPositioning : function(pc){
1358 this.applyStyles(pc);
1359 if(pc.right == "auto"){
1360 this.dom.style.right = "";
1362 if(pc.bottom == "auto"){
1363 this.dom.style.bottom = "";
1369 fixDisplay : function(){
1370 if(this.getStyle("display") == "none"){
1371 this.setStyle("visibility", "hidden");
1372 this.setStyle("display", this.originalDisplay); // first try reverting to default
1373 if(this.getStyle("display") == "none"){ // if that fails, default to block
1374 this.setStyle("display", "block");
1380 * Quick set left and top adding default units
1381 * @param {String} left The left CSS property value
1382 * @param {String} top The top CSS property value
1383 * @return {Roo.Element} this
1385 setLeftTop : function(left, top){
1386 this.dom.style.left = this.addUnits(left);
1387 this.dom.style.top = this.addUnits(top);
1392 * Move this element relative to its current position.
1393 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1394 * @param {Number} distance How far to move the element in pixels
1395 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1396 * @return {Roo.Element} this
1398 move : function(direction, distance, animate){
1399 var xy = this.getXY();
1400 direction = direction.toLowerCase();
1404 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1408 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1413 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1418 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1425 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1426 * @return {Roo.Element} this
1429 if(!this.isClipped){
1430 this.isClipped = true;
1431 this.originalClip = {
1432 "o": this.getStyle("overflow"),
1433 "x": this.getStyle("overflow-x"),
1434 "y": this.getStyle("overflow-y")
1436 this.setStyle("overflow", "hidden");
1437 this.setStyle("overflow-x", "hidden");
1438 this.setStyle("overflow-y", "hidden");
1444 * Return clipping (overflow) to original clipping before clip() was called
1445 * @return {Roo.Element} this
1447 unclip : function(){
1449 this.isClipped = false;
1450 var o = this.originalClip;
1451 if(o.o){this.setStyle("overflow", o.o);}
1452 if(o.x){this.setStyle("overflow-x", o.x);}
1453 if(o.y){this.setStyle("overflow-y", o.y);}
1460 * Gets the x,y coordinates specified by the anchor position on the element.
1461 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1462 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1463 * {width: (target width), height: (target height)} (defaults to the element's current size)
1464 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1465 * @return {Array} [x, y] An array containing the element's x and y coordinates
1467 getAnchorXY : function(anchor, local, s){
1468 //Passing a different size is useful for pre-calculating anchors,
1469 //especially for anchored animations that change the el size.
1471 var w, h, vp = false;
1474 if(d == document.body || d == document){
1476 w = D.getViewWidth(); h = D.getViewHeight();
1478 w = this.getWidth(); h = this.getHeight();
1481 w = s.width; h = s.height;
1483 var x = 0, y = 0, r = Math.round;
1484 switch((anchor || "tl").toLowerCase()){
1526 var sc = this.getScroll();
1527 return [x + sc.left, y + sc.top];
1529 //Add the element's offset xy
1530 var o = this.getXY();
1531 return [x+o[0], y+o[1]];
1535 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1536 * supported position values.
1537 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1538 * @param {String} position The position to align to.
1539 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1540 * @return {Array} [x, y]
1542 getAlignToXY : function(el, p, o){
1546 throw "Element.alignTo with an element that doesn't exist";
1548 var c = false; //constrain to viewport
1549 var p1 = "", p2 = "";
1556 }else if(p.indexOf("-") == -1){
1559 p = p.toLowerCase();
1560 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1562 throw "Element.alignTo with an invalid alignment " + p;
1564 p1 = m[1]; p2 = m[2]; c = !!m[3];
1566 //Subtract the aligned el's internal xy from the target's offset xy
1567 //plus custom offset to get the aligned el's new offset xy
1568 var a1 = this.getAnchorXY(p1, true);
1569 var a2 = el.getAnchorXY(p2, false);
1570 var x = a2[0] - a1[0] + o[0];
1571 var y = a2[1] - a1[1] + o[1];
1573 //constrain the aligned el to viewport if necessary
1574 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1575 // 5px of margin for ie
1576 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1578 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1579 //perpendicular to the vp border, allow the aligned el to slide on that border,
1580 //otherwise swap the aligned el to the opposite border of the target.
1581 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1582 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1583 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1584 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1587 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1588 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1590 if((x+w) > dw + scrollX){
1591 x = swapX ? r.left-w : dw+scrollX-w;
1594 x = swapX ? r.right : scrollX;
1596 if((y+h) > dh + scrollY){
1597 y = swapY ? r.top-h : dh+scrollY-h;
1600 y = swapY ? r.bottom : scrollY;
1607 getConstrainToXY : function(){
1608 var os = {top:0, left:0, bottom:0, right: 0};
1610 return function(el, local, offsets, proposedXY){
1612 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1614 var vw, vh, vx = 0, vy = 0;
1615 if(el.dom == document.body || el.dom == document){
1616 vw = Roo.lib.Dom.getViewWidth();
1617 vh = Roo.lib.Dom.getViewHeight();
1619 vw = el.dom.clientWidth;
1620 vh = el.dom.clientHeight;
1622 var vxy = el.getXY();
1628 var s = el.getScroll();
1630 vx += offsets.left + s.left;
1631 vy += offsets.top + s.top;
1633 vw -= offsets.right;
1634 vh -= offsets.bottom;
1639 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1640 var x = xy[0], y = xy[1];
1641 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1643 // only move it if it needs it
1646 // first validate right/bottom
1655 // then make sure top/left isn't negative
1664 return moved ? [x, y] : false;
1669 adjustForConstraints : function(xy, parent, offsets){
1670 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1674 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1675 * document it aligns it to the viewport.
1676 * The position parameter is optional, and can be specified in any one of the following formats:
1678 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1679 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1680 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1681 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1682 * <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
1683 * element's anchor point, and the second value is used as the target's anchor point.</li>
1685 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1686 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1687 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1688 * that specified in order to enforce the viewport constraints.
1689 * Following are all of the supported anchor positions:
1692 ----- -----------------------------
1693 tl The top left corner (default)
1694 t The center of the top edge
1695 tr The top right corner
1696 l The center of the left edge
1697 c In the center of the element
1698 r The center of the right edge
1699 bl The bottom left corner
1700 b The center of the bottom edge
1701 br The bottom right corner
1705 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1706 el.alignTo("other-el");
1708 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1709 el.alignTo("other-el", "tr?");
1711 // align the bottom right corner of el with the center left edge of other-el
1712 el.alignTo("other-el", "br-l?");
1714 // align the center of el with the bottom left corner of other-el and
1715 // adjust the x position by -6 pixels (and the y position by 0)
1716 el.alignTo("other-el", "c-bl", [-6, 0]);
1718 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1719 * @param {String} position The position to align to.
1720 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1721 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1722 * @return {Roo.Element} this
1724 alignTo : function(element, position, offsets, animate){
1725 var xy = this.getAlignToXY(element, position, offsets);
1726 this.setXY(xy, this.preanim(arguments, 3));
1731 * Anchors an element to another element and realigns it when the window is resized.
1732 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1733 * @param {String} position The position to align to.
1734 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1735 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1736 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1737 * is a number, it is used as the buffer delay (defaults to 50ms).
1738 * @param {Function} callback The function to call after the animation finishes
1739 * @return {Roo.Element} this
1741 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1742 var action = function(){
1743 this.alignTo(el, alignment, offsets, animate);
1744 Roo.callback(callback, this);
1746 Roo.EventManager.onWindowResize(action, this);
1747 var tm = typeof monitorScroll;
1748 if(tm != 'undefined'){
1749 Roo.EventManager.on(window, 'scroll', action, this,
1750 {buffer: tm == 'number' ? monitorScroll : 50});
1752 action.call(this); // align immediately
1756 * Clears any opacity settings from this element. Required in some cases for IE.
1757 * @return {Roo.Element} this
1759 clearOpacity : function(){
1760 if (window.ActiveXObject) {
1761 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1762 this.dom.style.filter = "";
1765 this.dom.style.opacity = "";
1766 this.dom.style["-moz-opacity"] = "";
1767 this.dom.style["-khtml-opacity"] = "";
1773 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1774 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1775 * @return {Roo.Element} this
1777 hide : function(animate){
1778 this.setVisible(false, this.preanim(arguments, 0));
1783 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1784 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1785 * @return {Roo.Element} this
1787 show : function(animate){
1788 this.setVisible(true, this.preanim(arguments, 0));
1793 * @private Test if size has a unit, otherwise appends the default
1795 addUnits : function(size){
1796 return Roo.Element.addUnits(size, this.defaultUnit);
1800 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1801 * @return {Roo.Element} this
1803 beginMeasure : function(){
1805 if(el.offsetWidth || el.offsetHeight){
1806 return this; // offsets work already
1809 var p = this.dom, b = document.body; // start with this element
1810 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1811 var pe = Roo.get(p);
1812 if(pe.getStyle('display') == 'none'){
1813 changed.push({el: p, visibility: pe.getStyle("visibility")});
1814 p.style.visibility = "hidden";
1815 p.style.display = "block";
1819 this._measureChanged = changed;
1825 * Restores displays to before beginMeasure was called
1826 * @return {Roo.Element} this
1828 endMeasure : function(){
1829 var changed = this._measureChanged;
1831 for(var i = 0, len = changed.length; i < len; i++) {
1833 r.el.style.visibility = r.visibility;
1834 r.el.style.display = "none";
1836 this._measureChanged = null;
1842 * Update the innerHTML of this element, optionally searching for and processing scripts
1843 * @param {String} html The new HTML
1844 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1845 * @param {Function} callback For async script loading you can be noticed when the update completes
1846 * @return {Roo.Element} this
1848 update : function(html, loadScripts, callback){
1849 if(typeof html == "undefined"){
1852 if(loadScripts !== true){
1853 this.dom.innerHTML = html;
1854 if(typeof callback == "function"){
1862 html += '<span id="' + id + '"></span>';
1864 E.onAvailable(id, function(){
1865 var hd = document.getElementsByTagName("head")[0];
1866 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1867 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1868 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1871 while(match = re.exec(html)){
1872 var attrs = match[1];
1873 var srcMatch = attrs ? attrs.match(srcRe) : false;
1874 if(srcMatch && srcMatch[2]){
1875 var s = document.createElement("script");
1876 s.src = srcMatch[2];
1877 var typeMatch = attrs.match(typeRe);
1878 if(typeMatch && typeMatch[2]){
1879 s.type = typeMatch[2];
1882 }else if(match[2] && match[2].length > 0){
1883 if(window.execScript) {
1884 window.execScript(match[2]);
1892 window.eval(match[2]);
1896 var el = document.getElementById(id);
1897 if(el){el.parentNode.removeChild(el);}
1898 if(typeof callback == "function"){
1902 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1907 * Direct access to the UpdateManager update() method (takes the same parameters).
1908 * @param {String/Function} url The url for this request or a function to call to get the url
1909 * @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}
1910 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1911 * @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.
1912 * @return {Roo.Element} this
1915 var um = this.getUpdateManager();
1916 um.update.apply(um, arguments);
1921 * Gets this element's UpdateManager
1922 * @return {Roo.UpdateManager} The UpdateManager
1924 getUpdateManager : function(){
1925 if(!this.updateManager){
1926 this.updateManager = new Roo.UpdateManager(this);
1928 return this.updateManager;
1932 * Disables text selection for this element (normalized across browsers)
1933 * @return {Roo.Element} this
1935 unselectable : function(){
1936 this.dom.unselectable = "on";
1937 this.swallowEvent("selectstart", true);
1938 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1939 this.addClass("x-unselectable");
1944 * Calculates the x, y to center this element on the screen
1945 * @return {Array} The x, y values [x, y]
1947 getCenterXY : function(){
1948 return this.getAlignToXY(document, 'c-c');
1952 * Centers the Element in either the viewport, or another Element.
1953 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1955 center : function(centerIn){
1956 this.alignTo(centerIn || document, 'c-c');
1961 * Tests various css rules/browsers to determine if this element uses a border box
1964 isBorderBox : function(){
1965 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1969 * Return a box {x, y, width, height} that can be used to set another elements
1970 * size/location to match this element.
1971 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1972 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1973 * @return {Object} box An object in the format {x, y, width, height}
1975 getBox : function(contentBox, local){
1980 var left = parseInt(this.getStyle("left"), 10) || 0;
1981 var top = parseInt(this.getStyle("top"), 10) || 0;
1984 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
1986 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
1988 var l = this.getBorderWidth("l")+this.getPadding("l");
1989 var r = this.getBorderWidth("r")+this.getPadding("r");
1990 var t = this.getBorderWidth("t")+this.getPadding("t");
1991 var b = this.getBorderWidth("b")+this.getPadding("b");
1992 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)};
1994 bx.right = bx.x + bx.width;
1995 bx.bottom = bx.y + bx.height;
2000 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2001 for more information about the sides.
2002 * @param {String} sides
2005 getFrameWidth : function(sides, onlyContentBox){
2006 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2010 * 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.
2011 * @param {Object} box The box to fill {x, y, width, height}
2012 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2013 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2014 * @return {Roo.Element} this
2016 setBox : function(box, adjust, animate){
2017 var w = box.width, h = box.height;
2018 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2019 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2020 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2022 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2027 * Forces the browser to repaint this element
2028 * @return {Roo.Element} this
2030 repaint : function(){
2032 this.addClass("x-repaint");
2033 setTimeout(function(){
2034 Roo.get(dom).removeClass("x-repaint");
2040 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2041 * then it returns the calculated width of the sides (see getPadding)
2042 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2043 * @return {Object/Number}
2045 getMargins : function(side){
2048 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2049 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2050 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2051 right: parseInt(this.getStyle("margin-right"), 10) || 0
2054 return this.addStyles(side, El.margins);
2059 addStyles : function(sides, styles){
2061 for(var i = 0, len = sides.length; i < len; i++){
2062 v = this.getStyle(styles[sides.charAt(i)]);
2064 w = parseInt(v, 10);
2072 * Creates a proxy element of this element
2073 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2074 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2075 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2076 * @return {Roo.Element} The new proxy element
2078 createProxy : function(config, renderTo, matchBox){
2080 renderTo = Roo.getDom(renderTo);
2082 renderTo = document.body;
2084 config = typeof config == "object" ?
2085 config : {tag : "div", cls: config};
2086 var proxy = Roo.DomHelper.append(renderTo, config, true);
2088 proxy.setBox(this.getBox());
2094 * Puts a mask over this element to disable user interaction. Requires core.css.
2095 * This method can only be applied to elements which accept child nodes.
2096 * @param {String} msg (optional) A message to display in the mask
2097 * @param {String} msgCls (optional) A css class to apply to the msg element
2098 * @return {Element} The mask element
2100 mask : function(msg, msgCls)
2102 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2103 this.setStyle("position", "relative");
2106 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2108 this.addClass("x-masked");
2109 this._mask.setDisplayed(true);
2114 while (dom && dom.style) {
2115 if (!isNaN(parseInt(dom.style.zIndex))) {
2116 z = Math.max(z, parseInt(dom.style.zIndex));
2118 dom = dom.parentNode;
2120 // if we are masking the body - then it hides everything..
2121 if (this.dom == document.body) {
2123 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2124 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2127 if(typeof msg == 'string'){
2129 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2131 var mm = this._maskMsg;
2132 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2133 if (mm.dom.firstChild) { // weird IE issue?
2134 mm.dom.firstChild.innerHTML = msg;
2136 mm.setDisplayed(true);
2138 mm.setStyle('z-index', z + 102);
2140 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2141 this._mask.setHeight(this.getHeight());
2143 this._mask.setStyle('z-index', z + 100);
2149 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2150 * it is cached for reuse.
2152 unmask : function(removeEl){
2154 if(removeEl === true){
2155 this._mask.remove();
2158 this._maskMsg.remove();
2159 delete this._maskMsg;
2162 this._mask.setDisplayed(false);
2164 this._maskMsg.setDisplayed(false);
2168 this.removeClass("x-masked");
2172 * Returns true if this element is masked
2175 isMasked : function(){
2176 return this._mask && this._mask.isVisible();
2180 * Creates an iframe shim for this element to keep selects and other windowed objects from
2182 * @return {Roo.Element} The new shim element
2184 createShim : function(){
2185 var el = document.createElement('iframe');
2186 el.frameBorder = 'no';
2187 el.className = 'roo-shim';
2188 if(Roo.isIE && Roo.isSecure){
2189 el.src = Roo.SSL_SECURE_URL;
2191 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2192 shim.autoBoxAdjust = false;
2197 * Removes this element from the DOM and deletes it from the cache
2199 remove : function(){
2200 if(this.dom.parentNode){
2201 this.dom.parentNode.removeChild(this.dom);
2203 delete El.cache[this.dom.id];
2207 * Sets up event handlers to add and remove a css class when the mouse is over this element
2208 * @param {String} className
2209 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2210 * mouseout events for children elements
2211 * @return {Roo.Element} this
2213 addClassOnOver : function(className, preventFlicker){
2214 this.on("mouseover", function(){
2215 Roo.fly(this, '_internal').addClass(className);
2217 var removeFn = function(e){
2218 if(preventFlicker !== true || !e.within(this, true)){
2219 Roo.fly(this, '_internal').removeClass(className);
2222 this.on("mouseout", removeFn, this.dom);
2227 * Sets up event handlers to add and remove a css class when this element has the focus
2228 * @param {String} className
2229 * @return {Roo.Element} this
2231 addClassOnFocus : function(className){
2232 this.on("focus", function(){
2233 Roo.fly(this, '_internal').addClass(className);
2235 this.on("blur", function(){
2236 Roo.fly(this, '_internal').removeClass(className);
2241 * 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)
2242 * @param {String} className
2243 * @return {Roo.Element} this
2245 addClassOnClick : function(className){
2247 this.on("mousedown", function(){
2248 Roo.fly(dom, '_internal').addClass(className);
2249 var d = Roo.get(document);
2250 var fn = function(){
2251 Roo.fly(dom, '_internal').removeClass(className);
2252 d.removeListener("mouseup", fn);
2254 d.on("mouseup", fn);
2260 * Stops the specified event from bubbling and optionally prevents the default action
2261 * @param {String} eventName
2262 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2263 * @return {Roo.Element} this
2265 swallowEvent : function(eventName, preventDefault){
2266 var fn = function(e){
2267 e.stopPropagation();
2272 if(eventName instanceof Array){
2273 for(var i = 0, len = eventName.length; i < len; i++){
2274 this.on(eventName[i], fn);
2278 this.on(eventName, fn);
2285 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2288 * Sizes this element to its parent element's dimensions performing
2289 * neccessary box adjustments.
2290 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2291 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2292 * @return {Roo.Element} this
2294 fitToParent : function(monitorResize, targetParent) {
2295 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2296 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2297 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2300 var p = Roo.get(targetParent || this.dom.parentNode);
2301 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2302 if (monitorResize === true) {
2303 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2304 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2310 * Gets the next sibling, skipping text nodes
2311 * @return {HTMLElement} The next sibling or null
2313 getNextSibling : function(){
2314 var n = this.dom.nextSibling;
2315 while(n && n.nodeType != 1){
2322 * Gets the previous sibling, skipping text nodes
2323 * @return {HTMLElement} The previous sibling or null
2325 getPrevSibling : function(){
2326 var n = this.dom.previousSibling;
2327 while(n && n.nodeType != 1){
2328 n = n.previousSibling;
2335 * Appends the passed element(s) to this element
2336 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2337 * @return {Roo.Element} this
2339 appendChild: function(el){
2346 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2347 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2348 * automatically generated with the specified attributes.
2349 * @param {HTMLElement} insertBefore (optional) a child element of this element
2350 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2351 * @return {Roo.Element} The new child element
2353 createChild: function(config, insertBefore, returnDom){
2354 config = config || {tag:'div'};
2356 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2358 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2362 * Appends this element to the passed element
2363 * @param {String/HTMLElement/Element} el The new parent element
2364 * @return {Roo.Element} this
2366 appendTo: function(el){
2367 el = Roo.getDom(el);
2368 el.appendChild(this.dom);
2373 * Inserts this element before the passed element in the DOM
2374 * @param {String/HTMLElement/Element} el The element to insert before
2375 * @return {Roo.Element} this
2377 insertBefore: function(el){
2378 el = Roo.getDom(el);
2379 el.parentNode.insertBefore(this.dom, el);
2384 * Inserts this element after the passed element in the DOM
2385 * @param {String/HTMLElement/Element} el The element to insert after
2386 * @return {Roo.Element} this
2388 insertAfter: function(el){
2389 el = Roo.getDom(el);
2390 el.parentNode.insertBefore(this.dom, el.nextSibling);
2395 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2396 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2397 * @return {Roo.Element} The new child
2399 insertFirst: function(el, returnDom){
2401 if(typeof el == 'object' && !el.nodeType){ // dh config
2402 return this.createChild(el, this.dom.firstChild, returnDom);
2404 el = Roo.getDom(el);
2405 this.dom.insertBefore(el, this.dom.firstChild);
2406 return !returnDom ? Roo.get(el) : el;
2411 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2412 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2413 * @param {String} where (optional) 'before' or 'after' defaults to before
2414 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2415 * @return {Roo.Element} the inserted Element
2417 insertSibling: function(el, where, returnDom){
2418 where = where ? where.toLowerCase() : 'before';
2420 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2422 if(typeof el == 'object' && !el.nodeType){ // dh config
2423 if(where == 'after' && !this.dom.nextSibling){
2424 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2426 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2430 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2431 where == 'before' ? this.dom : this.dom.nextSibling);
2440 * Creates and wraps this element with another element
2441 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2442 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2443 * @return {HTMLElement/Element} The newly created wrapper element
2445 wrap: function(config, returnDom){
2447 config = {tag: "div"};
2449 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2450 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2455 * Replaces the passed element with this element
2456 * @param {String/HTMLElement/Element} el The element to replace
2457 * @return {Roo.Element} this
2459 replace: function(el){
2461 this.insertBefore(el);
2467 * Inserts an html fragment into this element
2468 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2469 * @param {String} html The HTML fragment
2470 * @param {Boolean} returnEl True to return an Roo.Element
2471 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2473 insertHtml : function(where, html, returnEl){
2474 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2475 return returnEl ? Roo.get(el) : el;
2479 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2480 * @param {Object} o The object with the attributes
2481 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2482 * @return {Roo.Element} this
2484 set : function(o, useSet){
2486 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2488 if(attr == "style" || typeof o[attr] == "function") { continue; }
2490 el.className = o["cls"];
2493 el.setAttribute(attr, o[attr]);
2500 Roo.DomHelper.applyStyles(el, o.style);
2506 * Convenience method for constructing a KeyMap
2507 * @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:
2508 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2509 * @param {Function} fn The function to call
2510 * @param {Object} scope (optional) The scope of the function
2511 * @return {Roo.KeyMap} The KeyMap created
2513 addKeyListener : function(key, fn, scope){
2515 if(typeof key != "object" || key instanceof Array){
2531 return new Roo.KeyMap(this, config);
2535 * Creates a KeyMap for this element
2536 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2537 * @return {Roo.KeyMap} The KeyMap created
2539 addKeyMap : function(config){
2540 return new Roo.KeyMap(this, config);
2544 * Returns true if this element is scrollable.
2547 isScrollable : function(){
2549 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2553 * 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().
2554 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2555 * @param {Number} value The new scroll value
2556 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2557 * @return {Element} this
2560 scrollTo : function(side, value, animate){
2561 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2563 this.dom[prop] = value;
2565 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2566 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2572 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2573 * within this element's scrollable range.
2574 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2575 * @param {Number} distance How far to scroll the element in pixels
2576 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2577 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2578 * was scrolled as far as it could go.
2580 scroll : function(direction, distance, animate){
2581 if(!this.isScrollable()){
2585 var l = el.scrollLeft, t = el.scrollTop;
2586 var w = el.scrollWidth, h = el.scrollHeight;
2587 var cw = el.clientWidth, ch = el.clientHeight;
2588 direction = direction.toLowerCase();
2589 var scrolled = false;
2590 var a = this.preanim(arguments, 2);
2595 var v = Math.min(l + distance, w-cw);
2596 this.scrollTo("left", v, a);
2603 var v = Math.max(l - distance, 0);
2604 this.scrollTo("left", v, a);
2612 var v = Math.max(t - distance, 0);
2613 this.scrollTo("top", v, a);
2621 var v = Math.min(t + distance, h-ch);
2622 this.scrollTo("top", v, a);
2631 * Translates the passed page coordinates into left/top css values for this element
2632 * @param {Number/Array} x The page x or an array containing [x, y]
2633 * @param {Number} y The page y
2634 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2636 translatePoints : function(x, y){
2637 if(typeof x == 'object' || x instanceof Array){
2640 var p = this.getStyle('position');
2641 var o = this.getXY();
2643 var l = parseInt(this.getStyle('left'), 10);
2644 var t = parseInt(this.getStyle('top'), 10);
2647 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2650 t = (p == "relative") ? 0 : this.dom.offsetTop;
2653 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2657 * Returns the current scroll position of the element.
2658 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2660 getScroll : function(){
2661 var d = this.dom, doc = document;
2662 if(d == doc || d == doc.body){
2663 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2664 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2665 return {left: l, top: t};
2667 return {left: d.scrollLeft, top: d.scrollTop};
2672 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2673 * are convert to standard 6 digit hex color.
2674 * @param {String} attr The css attribute
2675 * @param {String} defaultValue The default value to use when a valid color isn't found
2676 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2679 getColor : function(attr, defaultValue, prefix){
2680 var v = this.getStyle(attr);
2681 if(!v || v == "transparent" || v == "inherit") {
2682 return defaultValue;
2684 var color = typeof prefix == "undefined" ? "#" : prefix;
2685 if(v.substr(0, 4) == "rgb("){
2686 var rvs = v.slice(4, v.length -1).split(",");
2687 for(var i = 0; i < 3; i++){
2688 var h = parseInt(rvs[i]).toString(16);
2695 if(v.substr(0, 1) == "#"){
2697 for(var i = 1; i < 4; i++){
2698 var c = v.charAt(i);
2701 }else if(v.length == 7){
2702 color += v.substr(1);
2706 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2710 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2711 * gradient background, rounded corners and a 4-way shadow.
2712 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2713 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2714 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2715 * @return {Roo.Element} this
2717 boxWrap : function(cls){
2718 cls = cls || 'x-box';
2719 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2720 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2725 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2726 * @param {String} namespace The namespace in which to look for the attribute
2727 * @param {String} name The attribute name
2728 * @return {String} The attribute value
2730 getAttributeNS : Roo.isIE ? function(ns, name){
2732 var type = typeof d[ns+":"+name];
2733 if(type != 'undefined' && type != 'unknown'){
2734 return d[ns+":"+name];
2737 } : function(ns, name){
2739 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2744 * Sets or Returns the value the dom attribute value
2745 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2746 * @param {String} value (optional) The value to set the attribute to
2747 * @return {String} The attribute value
2749 attr : function(name){
2750 if (arguments.length > 1) {
2751 this.dom.setAttribute(name, arguments[1]);
2752 return arguments[1];
2754 if (typeof(name) == 'object') {
2755 for(var i in name) {
2756 this.attr(i, name[i]);
2762 if (!this.dom.hasAttribute(name)) {
2765 return this.dom.getAttribute(name);
2772 var ep = El.prototype;
2775 * Appends an event handler (Shorthand for addListener)
2776 * @param {String} eventName The type of event to append
2777 * @param {Function} fn The method the event invokes
2778 * @param {Object} scope (optional) The scope (this object) of the fn
2779 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2782 ep.on = ep.addListener;
2784 ep.mon = ep.addListener;
2787 * Removes an event handler from this element (shorthand for removeListener)
2788 * @param {String} eventName the type of event to remove
2789 * @param {Function} fn the method the event invokes
2790 * @return {Roo.Element} this
2793 ep.un = ep.removeListener;
2796 * true to automatically adjust width and height settings for box-model issues (default to true)
2798 ep.autoBoxAdjust = true;
2801 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2804 El.addUnits = function(v, defaultUnit){
2805 if(v === "" || v == "auto"){
2808 if(v === undefined){
2811 if(typeof v == "number" || !El.unitPattern.test(v)){
2812 return v + (defaultUnit || 'px');
2817 // special markup used throughout Roo when box wrapping elements
2818 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>';
2820 * Visibility mode constant - Use visibility to hide element
2826 * Visibility mode constant - Use display to hide element
2832 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2833 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2834 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2846 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2847 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2848 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2849 * @return {Element} The Element object
2852 El.get = function(el){
2854 if(!el){ return null; }
2855 if(typeof el == "string"){ // element id
2856 if(!(elm = document.getElementById(el))){
2859 if(ex = El.cache[el]){
2862 ex = El.cache[el] = new El(elm);
2865 }else if(el.tagName){ // dom element
2869 if(ex = El.cache[id]){
2872 ex = El.cache[id] = new El(el);
2875 }else if(el instanceof El){
2877 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2878 // catch case where it hasn't been appended
2879 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2882 }else if(el.isComposite){
2884 }else if(el instanceof Array){
2885 return El.select(el);
2886 }else if(el == document){
2887 // create a bogus element object representing the document object
2889 var f = function(){};
2890 f.prototype = El.prototype;
2892 docEl.dom = document;
2900 El.uncache = function(el){
2901 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2903 delete El.cache[a[i].id || a[i]];
2909 // Garbage collection - uncache elements/purge listeners on orphaned elements
2910 // so we don't hold a reference and cause the browser to retain them
2911 El.garbageCollect = function(){
2912 if(!Roo.enableGarbageCollector){
2913 clearInterval(El.collectorThread);
2916 for(var eid in El.cache){
2917 var el = El.cache[eid], d = el.dom;
2918 // -------------------------------------------------------
2919 // Determining what is garbage:
2920 // -------------------------------------------------------
2922 // dom node is null, definitely garbage
2923 // -------------------------------------------------------
2925 // no parentNode == direct orphan, definitely garbage
2926 // -------------------------------------------------------
2927 // !d.offsetParent && !document.getElementById(eid)
2928 // display none elements have no offsetParent so we will
2929 // also try to look it up by it's id. However, check
2930 // offsetParent first so we don't do unneeded lookups.
2931 // This enables collection of elements that are not orphans
2932 // directly, but somewhere up the line they have an orphan
2934 // -------------------------------------------------------
2935 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2936 delete El.cache[eid];
2937 if(d && Roo.enableListenerCollection){
2943 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2947 El.Flyweight = function(dom){
2950 El.Flyweight.prototype = El.prototype;
2952 El._flyweights = {};
2954 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2955 * the dom node can be overwritten by other code.
2956 * @param {String/HTMLElement} el The dom node or id
2957 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2958 * prevent conflicts (e.g. internally Roo uses "_internal")
2960 * @return {Element} The shared Element object
2962 El.fly = function(el, named){
2963 named = named || '_global';
2964 el = Roo.getDom(el);
2968 if(!El._flyweights[named]){
2969 El._flyweights[named] = new El.Flyweight();
2971 El._flyweights[named].dom = el;
2972 return El._flyweights[named];
2976 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2977 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2978 * Shorthand of {@link Roo.Element#get}
2979 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2980 * @return {Element} The Element object
2986 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2987 * the dom node can be overwritten by other code.
2988 * Shorthand of {@link Roo.Element#fly}
2989 * @param {String/HTMLElement} el The dom node or id
2990 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2991 * prevent conflicts (e.g. internally Roo uses "_internal")
2993 * @return {Element} The shared Element object
2999 // speedy lookup for elements never to box adjust
3000 var noBoxAdjust = Roo.isStrict ? {
3003 input:1, select:1, textarea:1
3005 if(Roo.isIE || Roo.isGecko){
3006 noBoxAdjust['button'] = 1;
3010 Roo.EventManager.on(window, 'unload', function(){
3012 delete El._flyweights;
3020 Roo.Element.selectorFunction = Roo.DomQuery.select;
3023 Roo.Element.select = function(selector, unique, root){
3025 if(typeof selector == "string"){
3026 els = Roo.Element.selectorFunction(selector, root);
3027 }else if(selector.length !== undefined){
3030 throw "Invalid selector";
3032 if(unique === true){
3033 return new Roo.CompositeElement(els);
3035 return new Roo.CompositeElementLite(els);
3039 * Selects elements based on the passed CSS selector to enable working on them as 1.
3040 * @param {String/Array} selector The CSS selector or an array of elements
3041 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3042 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3043 * @return {CompositeElementLite/CompositeElement}
3047 Roo.select = Roo.Element.select;