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'
211 el = Roo.get(el.dom.parentNode);
214 Roo.log(el.getStyle('overflow'));
215 Roo.log(el.getStyle('overflow-y'));
216 Roo.log(el.getStyle('overflow-x'));
220 if(!el.isScrollable()){
228 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
229 * This is a shortcut for findParentNode() that always returns an Roo.Element.
230 * @param {String} selector The simple selector to test
231 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
232 search as a number or element (defaults to 10 || document.body)
233 * @return {Roo.Element} The matching DOM node (or null if no match was found)
235 up : function(simpleSelector, maxDepth){
236 return this.findParentNode(simpleSelector, maxDepth, true);
242 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
243 * @param {String} selector The simple selector to test
244 * @return {Boolean} True if this element matches the selector, else false
246 is : function(simpleSelector){
247 return Roo.DomQuery.is(this.dom, simpleSelector);
251 * Perform animation on this element.
252 * @param {Object} args The YUI animation control args
253 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
254 * @param {Function} onComplete (optional) Function to call when animation completes
255 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
256 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
257 * @return {Roo.Element} this
259 animate : function(args, duration, onComplete, easing, animType){
260 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
265 * @private Internal animation call
267 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
268 animType = animType || 'run';
270 var anim = Roo.lib.Anim[animType](
272 (opt.duration || defaultDur) || .35,
273 (opt.easing || defaultEase) || 'easeOut',
275 Roo.callback(cb, this);
276 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
284 // private legacy anim prep
285 preanim : function(a, i){
286 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
290 * Removes worthless text nodes
291 * @param {Boolean} forceReclean (optional) By default the element
292 * keeps track if it has been cleaned already so
293 * you can call this over and over. However, if you update the element and
294 * need to force a reclean, you can pass true.
296 clean : function(forceReclean){
297 if(this.isCleaned && forceReclean !== true){
301 var d = this.dom, n = d.firstChild, ni = -1;
303 var nx = n.nextSibling;
304 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
311 this.isCleaned = true;
316 calcOffsetsTo : function(el){
319 var restorePos = false;
320 if(el.getStyle('position') == 'static'){
321 el.position('relative');
326 while(op && op != d && op.tagName != 'HTML'){
329 op = op.offsetParent;
332 el.position('static');
338 * Scrolls this element into view within the passed container.
339 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
340 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
341 * @return {Roo.Element} this
343 scrollIntoView : function(container, hscroll){
344 var c = Roo.getDom(container) || document.body;
347 var o = this.calcOffsetsTo(c),
350 b = t+el.offsetHeight,
351 r = l+el.offsetWidth;
353 var ch = c.clientHeight;
354 var ct = parseInt(c.scrollTop, 10);
355 var cl = parseInt(c.scrollLeft, 10);
357 var cr = cl + c.clientWidth;
365 if(hscroll !== false){
369 c.scrollLeft = r-c.clientWidth;
376 scrollChildIntoView : function(child, hscroll){
377 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
381 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
382 * the new height may not be available immediately.
383 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
384 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
385 * @param {Function} onComplete (optional) Function to call when animation completes
386 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
387 * @return {Roo.Element} this
389 autoHeight : function(animate, duration, onComplete, easing){
390 var oldHeight = this.getHeight();
392 this.setHeight(1); // force clipping
393 setTimeout(function(){
394 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
396 this.setHeight(height);
398 if(typeof onComplete == "function"){
402 this.setHeight(oldHeight); // restore original height
403 this.setHeight(height, animate, duration, function(){
405 if(typeof onComplete == "function") { onComplete(); }
406 }.createDelegate(this), easing);
408 }.createDelegate(this), 0);
413 * Returns true if this element is an ancestor of the passed element
414 * @param {HTMLElement/String} el The element to check
415 * @return {Boolean} True if this element is an ancestor of el, else false
417 contains : function(el){
418 if(!el){return false;}
419 return D.isAncestor(this.dom, el.dom ? el.dom : el);
423 * Checks whether the element is currently visible using both visibility and display properties.
424 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
425 * @return {Boolean} True if the element is currently visible, else false
427 isVisible : function(deep) {
428 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
429 if(deep !== true || !vis){
432 var p = this.dom.parentNode;
433 while(p && p.tagName.toLowerCase() != "body"){
434 if(!Roo.fly(p, '_isVisible').isVisible()){
443 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
444 * @param {String} selector The CSS selector
445 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
446 * @return {CompositeElement/CompositeElementLite} The composite element
448 select : function(selector, unique){
449 return El.select(selector, unique, this.dom);
453 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
454 * @param {String} selector The CSS selector
455 * @return {Array} An array of the matched nodes
457 query : function(selector, unique){
458 return Roo.DomQuery.select(selector, this.dom);
462 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
463 * @param {String} selector The CSS selector
464 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
465 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
467 child : function(selector, returnDom){
468 var n = Roo.DomQuery.selectNode(selector, this.dom);
469 return returnDom ? n : Roo.get(n);
473 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
474 * @param {String} selector The CSS selector
475 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
476 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
478 down : function(selector, returnDom){
479 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
480 return returnDom ? n : Roo.get(n);
484 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
485 * @param {String} group The group the DD object is member of
486 * @param {Object} config The DD config object
487 * @param {Object} overrides An object containing methods to override/implement on the DD object
488 * @return {Roo.dd.DD} The DD object
490 initDD : function(group, config, overrides){
491 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
492 return Roo.apply(dd, overrides);
496 * Initializes a {@link Roo.dd.DDProxy} object for this element.
497 * @param {String} group The group the DDProxy object is member of
498 * @param {Object} config The DDProxy config object
499 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
500 * @return {Roo.dd.DDProxy} The DDProxy object
502 initDDProxy : function(group, config, overrides){
503 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
504 return Roo.apply(dd, overrides);
508 * Initializes a {@link Roo.dd.DDTarget} object for this element.
509 * @param {String} group The group the DDTarget object is member of
510 * @param {Object} config The DDTarget config object
511 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
512 * @return {Roo.dd.DDTarget} The DDTarget object
514 initDDTarget : function(group, config, overrides){
515 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
516 return Roo.apply(dd, overrides);
520 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
521 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
522 * @param {Boolean} visible Whether the element is visible
523 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
524 * @return {Roo.Element} this
526 setVisible : function(visible, animate){
528 if(this.visibilityMode == El.DISPLAY){
529 this.setDisplayed(visible);
532 this.dom.style.visibility = visible ? "visible" : "hidden";
535 // closure for composites
537 var visMode = this.visibilityMode;
539 this.setOpacity(.01);
540 this.setVisible(true);
542 this.anim({opacity: { to: (visible?1:0) }},
543 this.preanim(arguments, 1),
544 null, .35, 'easeIn', function(){
546 if(visMode == El.DISPLAY){
547 dom.style.display = "none";
549 dom.style.visibility = "hidden";
551 Roo.get(dom).setOpacity(1);
559 * Returns true if display is not "none"
562 isDisplayed : function() {
563 return this.getStyle("display") != "none";
567 * Toggles the element's visibility or display, depending on visibility mode.
568 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
569 * @return {Roo.Element} this
571 toggle : function(animate){
572 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
577 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
578 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
579 * @return {Roo.Element} this
581 setDisplayed : function(value) {
582 if(typeof value == "boolean"){
583 value = value ? this.originalDisplay : "none";
585 this.setStyle("display", value);
590 * Tries to focus the element. Any exceptions are caught and ignored.
591 * @return {Roo.Element} this
601 * Tries to blur the element. Any exceptions are caught and ignored.
602 * @return {Roo.Element} this
612 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
613 * @param {String/Array} className The CSS class to add, or an array of classes
614 * @return {Roo.Element} this
616 addClass : function(className){
617 if(className instanceof Array){
618 for(var i = 0, len = className.length; i < len; i++) {
619 this.addClass(className[i]);
622 if(className && !this.hasClass(className)){
623 this.dom.className = this.dom.className + " " + className;
630 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
631 * @param {String/Array} className The CSS class to add, or an array of classes
632 * @return {Roo.Element} this
634 radioClass : function(className){
635 var siblings = this.dom.parentNode.childNodes;
636 for(var i = 0; i < siblings.length; i++) {
639 Roo.get(s).removeClass(className);
642 this.addClass(className);
647 * Removes one or more CSS classes from the element.
648 * @param {String/Array} className The CSS class to remove, or an array of classes
649 * @return {Roo.Element} this
651 removeClass : function(className){
652 if(!className || !this.dom.className){
655 if(className instanceof Array){
656 for(var i = 0, len = className.length; i < len; i++) {
657 this.removeClass(className[i]);
660 if(this.hasClass(className)){
661 var re = this.classReCache[className];
663 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
664 this.classReCache[className] = re;
667 this.dom.className.replace(re, " ");
677 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
678 * @param {String} className The CSS class to toggle
679 * @return {Roo.Element} this
681 toggleClass : function(className){
682 if(this.hasClass(className)){
683 this.removeClass(className);
685 this.addClass(className);
691 * Checks if the specified CSS class exists on this element's DOM node.
692 * @param {String} className The CSS class to check for
693 * @return {Boolean} True if the class exists, else false
695 hasClass : function(className){
696 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
700 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
701 * @param {String} oldClassName The CSS class to replace
702 * @param {String} newClassName The replacement CSS class
703 * @return {Roo.Element} this
705 replaceClass : function(oldClassName, newClassName){
706 this.removeClass(oldClassName);
707 this.addClass(newClassName);
712 * Returns an object with properties matching the styles requested.
713 * For example, el.getStyles('color', 'font-size', 'width') might return
714 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
715 * @param {String} style1 A style name
716 * @param {String} style2 A style name
717 * @param {String} etc.
718 * @return {Object} The style object
720 getStyles : function(){
721 var a = arguments, len = a.length, r = {};
722 for(var i = 0; i < len; i++){
723 r[a[i]] = this.getStyle(a[i]);
729 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
730 * @param {String} property The style property whose value is returned.
731 * @return {String} The current value of the style property for this element.
733 getStyle : function(){
734 return view && view.getComputedStyle ?
736 var el = this.dom, v, cs, camel;
740 if(el.style && (v = el.style[prop])){
743 if(cs = view.getComputedStyle(el, "")){
744 if(!(camel = propCache[prop])){
745 camel = propCache[prop] = prop.replace(camelRe, camelFn);
752 var el = this.dom, v, cs, camel;
753 if(prop == 'opacity'){
754 if(typeof el.style.filter == 'string'){
755 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
757 var fv = parseFloat(m[1]);
759 return fv ? fv / 100 : 0;
764 }else if(prop == 'float'){
767 if(!(camel = propCache[prop])){
768 camel = propCache[prop] = prop.replace(camelRe, camelFn);
770 if(v = el.style[camel]){
773 if(cs = el.currentStyle){
781 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
782 * @param {String/Object} property The style property to be set, or an object of multiple styles.
783 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
784 * @return {Roo.Element} this
786 setStyle : function(prop, value){
787 if(typeof prop == "string"){
789 if (prop == 'float') {
790 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
795 if(!(camel = propCache[prop])){
796 camel = propCache[prop] = prop.replace(camelRe, camelFn);
799 if(camel == 'opacity') {
800 this.setOpacity(value);
802 this.dom.style[camel] = value;
805 for(var style in prop){
806 if(typeof prop[style] != "function"){
807 this.setStyle(style, prop[style]);
815 * More flexible version of {@link #setStyle} for setting style properties.
816 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
817 * a function which returns such a specification.
818 * @return {Roo.Element} this
820 applyStyles : function(style){
821 Roo.DomHelper.applyStyles(this.dom, style);
826 * 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).
827 * @return {Number} The X position of the element
830 return D.getX(this.dom);
834 * 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).
835 * @return {Number} The Y position of the element
838 return D.getY(this.dom);
842 * 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).
843 * @return {Array} The XY position of the element
846 return D.getXY(this.dom);
850 * 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).
851 * @param {Number} The X 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 setX : function(x, animate){
859 this.setXY([x, this.getY()], this.preanim(arguments, 1));
865 * 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).
866 * @param {Number} The Y position of the element
867 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
868 * @return {Roo.Element} this
870 setY : function(y, animate){
874 this.setXY([this.getX(), y], this.preanim(arguments, 1));
880 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
881 * @param {String} left The left CSS property value
882 * @return {Roo.Element} this
884 setLeft : function(left){
885 this.setStyle("left", this.addUnits(left));
890 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
891 * @param {String} top The top CSS property value
892 * @return {Roo.Element} this
894 setTop : function(top){
895 this.setStyle("top", this.addUnits(top));
900 * Sets the element's CSS right style.
901 * @param {String} right The right CSS property value
902 * @return {Roo.Element} this
904 setRight : function(right){
905 this.setStyle("right", this.addUnits(right));
910 * Sets the element's CSS bottom style.
911 * @param {String} bottom The bottom CSS property value
912 * @return {Roo.Element} this
914 setBottom : function(bottom){
915 this.setStyle("bottom", this.addUnits(bottom));
920 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
921 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
922 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
923 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
924 * @return {Roo.Element} this
926 setXY : function(pos, animate){
928 D.setXY(this.dom, pos);
930 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
936 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
937 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
938 * @param {Number} x X value for new position (coordinates are page-based)
939 * @param {Number} y Y value for new position (coordinates are page-based)
940 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
941 * @return {Roo.Element} this
943 setLocation : function(x, y, animate){
944 this.setXY([x, y], this.preanim(arguments, 2));
949 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
950 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
951 * @param {Number} x X value for new position (coordinates are page-based)
952 * @param {Number} y Y value for new position (coordinates are page-based)
953 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
954 * @return {Roo.Element} this
956 moveTo : function(x, y, animate){
957 this.setXY([x, y], this.preanim(arguments, 2));
962 * Returns the region of the given element.
963 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
964 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
966 getRegion : function(){
967 return D.getRegion(this.dom);
971 * Returns the offset height of the element
972 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
973 * @return {Number} The element's height
975 getHeight : function(contentHeight){
976 var h = this.dom.offsetHeight || 0;
977 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
981 * Returns the offset width of the element
982 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
983 * @return {Number} The element's width
985 getWidth : function(contentWidth){
986 var w = this.dom.offsetWidth || 0;
987 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
991 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
992 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
993 * if a height has not been set using CSS.
996 getComputedHeight : function(){
997 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
999 h = parseInt(this.getStyle('height'), 10) || 0;
1000 if(!this.isBorderBox()){
1001 h += this.getFrameWidth('tb');
1008 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1009 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1010 * if a width has not been set using CSS.
1013 getComputedWidth : function(){
1014 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1016 w = parseInt(this.getStyle('width'), 10) || 0;
1017 if(!this.isBorderBox()){
1018 w += this.getFrameWidth('lr');
1025 * Returns the size of the element.
1026 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1027 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1029 getSize : function(contentSize){
1030 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1034 * Returns the width and height of the viewport.
1035 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1037 getViewSize : function(){
1038 var d = this.dom, doc = document, aw = 0, ah = 0;
1039 if(d == doc || d == doc.body){
1040 return {width : D.getViewWidth(), height: D.getViewHeight()};
1043 width : d.clientWidth,
1044 height: d.clientHeight
1050 * Returns the value of the "value" attribute
1051 * @param {Boolean} asNumber true to parse the value as a number
1052 * @return {String/Number}
1054 getValue : function(asNumber){
1055 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1059 adjustWidth : function(width){
1060 if(typeof width == "number"){
1061 if(this.autoBoxAdjust && !this.isBorderBox()){
1062 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1072 adjustHeight : function(height){
1073 if(typeof height == "number"){
1074 if(this.autoBoxAdjust && !this.isBorderBox()){
1075 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1085 * Set the width of the element
1086 * @param {Number} width The new width
1087 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1088 * @return {Roo.Element} this
1090 setWidth : function(width, animate){
1091 width = this.adjustWidth(width);
1093 this.dom.style.width = this.addUnits(width);
1095 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1101 * Set the height of the element
1102 * @param {Number} height The new height
1103 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1104 * @return {Roo.Element} this
1106 setHeight : function(height, animate){
1107 height = this.adjustHeight(height);
1109 this.dom.style.height = this.addUnits(height);
1111 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1117 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1118 * @param {Number} width The new width
1119 * @param {Number} height The new height
1120 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1121 * @return {Roo.Element} this
1123 setSize : function(width, height, animate){
1124 if(typeof width == "object"){ // in case of object from getSize()
1125 height = width.height; width = width.width;
1127 width = this.adjustWidth(width); height = this.adjustHeight(height);
1129 this.dom.style.width = this.addUnits(width);
1130 this.dom.style.height = this.addUnits(height);
1132 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1138 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1139 * @param {Number} x X value for new position (coordinates are page-based)
1140 * @param {Number} y Y value for new position (coordinates are page-based)
1141 * @param {Number} width The new width
1142 * @param {Number} height The new height
1143 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1144 * @return {Roo.Element} this
1146 setBounds : function(x, y, width, height, animate){
1148 this.setSize(width, height);
1149 this.setLocation(x, y);
1151 width = this.adjustWidth(width); height = this.adjustHeight(height);
1152 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1153 this.preanim(arguments, 4), 'motion');
1159 * 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.
1160 * @param {Roo.lib.Region} region The region to fill
1161 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1162 * @return {Roo.Element} this
1164 setRegion : function(region, animate){
1165 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1170 * Appends an event handler
1172 * @param {String} eventName The type of event to append
1173 * @param {Function} fn The method the event invokes
1174 * @param {Object} scope (optional) The scope (this object) of the fn
1175 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1177 addListener : function(eventName, fn, scope, options){
1179 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1184 * Removes an event handler from this element
1185 * @param {String} eventName the type of event to remove
1186 * @param {Function} fn the method the event invokes
1187 * @return {Roo.Element} this
1189 removeListener : function(eventName, fn){
1190 Roo.EventManager.removeListener(this.dom, eventName, fn);
1195 * Removes all previous added listeners from this element
1196 * @return {Roo.Element} this
1198 removeAllListeners : function(){
1199 E.purgeElement(this.dom);
1203 relayEvent : function(eventName, observable){
1204 this.on(eventName, function(e){
1205 observable.fireEvent(eventName, e);
1210 * Set the opacity of the element
1211 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1212 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1213 * @return {Roo.Element} this
1215 setOpacity : function(opacity, animate){
1217 var s = this.dom.style;
1220 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1221 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1223 s.opacity = opacity;
1226 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1232 * Gets the left X coordinate
1233 * @param {Boolean} local True to get the local css position instead of page coordinate
1236 getLeft : function(local){
1240 return parseInt(this.getStyle("left"), 10) || 0;
1245 * Gets the right X coordinate of the element (element X position + element width)
1246 * @param {Boolean} local True to get the local css position instead of page coordinate
1249 getRight : function(local){
1251 return this.getX() + this.getWidth();
1253 return (this.getLeft(true) + this.getWidth()) || 0;
1258 * Gets the top Y coordinate
1259 * @param {Boolean} local True to get the local css position instead of page coordinate
1262 getTop : function(local) {
1266 return parseInt(this.getStyle("top"), 10) || 0;
1271 * Gets the bottom Y coordinate of the element (element Y position + element height)
1272 * @param {Boolean} local True to get the local css position instead of page coordinate
1275 getBottom : function(local){
1277 return this.getY() + this.getHeight();
1279 return (this.getTop(true) + this.getHeight()) || 0;
1284 * Initializes positioning on this element. If a desired position is not passed, it will make the
1285 * the element positioned relative IF it is not already positioned.
1286 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1287 * @param {Number} zIndex (optional) The zIndex to apply
1288 * @param {Number} x (optional) Set the page X position
1289 * @param {Number} y (optional) Set the page Y position
1291 position : function(pos, zIndex, x, y){
1293 if(this.getStyle('position') == 'static'){
1294 this.setStyle('position', 'relative');
1297 this.setStyle("position", pos);
1300 this.setStyle("z-index", zIndex);
1302 if(x !== undefined && y !== undefined){
1304 }else if(x !== undefined){
1306 }else if(y !== undefined){
1312 * Clear positioning back to the default when the document was loaded
1313 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1314 * @return {Roo.Element} this
1316 clearPositioning : function(value){
1324 "position" : "static"
1330 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1331 * snapshot before performing an update and then restoring the element.
1334 getPositioning : function(){
1335 var l = this.getStyle("left");
1336 var t = this.getStyle("top");
1338 "position" : this.getStyle("position"),
1340 "right" : l ? "" : this.getStyle("right"),
1342 "bottom" : t ? "" : this.getStyle("bottom"),
1343 "z-index" : this.getStyle("z-index")
1348 * Gets the width of the border(s) for the specified side(s)
1349 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1350 * passing lr would get the border (l)eft width + the border (r)ight width.
1351 * @return {Number} The width of the sides passed added together
1353 getBorderWidth : function(side){
1354 return this.addStyles(side, El.borders);
1358 * Gets the width of the padding(s) for the specified side(s)
1359 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1360 * passing lr would get the padding (l)eft + the padding (r)ight.
1361 * @return {Number} The padding of the sides passed added together
1363 getPadding : function(side){
1364 return this.addStyles(side, El.paddings);
1368 * Set positioning with an object returned by getPositioning().
1369 * @param {Object} posCfg
1370 * @return {Roo.Element} this
1372 setPositioning : function(pc){
1373 this.applyStyles(pc);
1374 if(pc.right == "auto"){
1375 this.dom.style.right = "";
1377 if(pc.bottom == "auto"){
1378 this.dom.style.bottom = "";
1384 fixDisplay : function(){
1385 if(this.getStyle("display") == "none"){
1386 this.setStyle("visibility", "hidden");
1387 this.setStyle("display", this.originalDisplay); // first try reverting to default
1388 if(this.getStyle("display") == "none"){ // if that fails, default to block
1389 this.setStyle("display", "block");
1395 * Quick set left and top adding default units
1396 * @param {String} left The left CSS property value
1397 * @param {String} top The top CSS property value
1398 * @return {Roo.Element} this
1400 setLeftTop : function(left, top){
1401 this.dom.style.left = this.addUnits(left);
1402 this.dom.style.top = this.addUnits(top);
1407 * Move this element relative to its current position.
1408 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1409 * @param {Number} distance How far to move the element in pixels
1410 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1411 * @return {Roo.Element} this
1413 move : function(direction, distance, animate){
1414 var xy = this.getXY();
1415 direction = direction.toLowerCase();
1419 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1423 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1428 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1433 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1440 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1441 * @return {Roo.Element} this
1444 if(!this.isClipped){
1445 this.isClipped = true;
1446 this.originalClip = {
1447 "o": this.getStyle("overflow"),
1448 "x": this.getStyle("overflow-x"),
1449 "y": this.getStyle("overflow-y")
1451 this.setStyle("overflow", "hidden");
1452 this.setStyle("overflow-x", "hidden");
1453 this.setStyle("overflow-y", "hidden");
1459 * Return clipping (overflow) to original clipping before clip() was called
1460 * @return {Roo.Element} this
1462 unclip : function(){
1464 this.isClipped = false;
1465 var o = this.originalClip;
1466 if(o.o){this.setStyle("overflow", o.o);}
1467 if(o.x){this.setStyle("overflow-x", o.x);}
1468 if(o.y){this.setStyle("overflow-y", o.y);}
1475 * Gets the x,y coordinates specified by the anchor position on the element.
1476 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1477 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1478 * {width: (target width), height: (target height)} (defaults to the element's current size)
1479 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1480 * @return {Array} [x, y] An array containing the element's x and y coordinates
1482 getAnchorXY : function(anchor, local, s){
1483 //Passing a different size is useful for pre-calculating anchors,
1484 //especially for anchored animations that change the el size.
1486 var w, h, vp = false;
1489 if(d == document.body || d == document){
1491 w = D.getViewWidth(); h = D.getViewHeight();
1493 w = this.getWidth(); h = this.getHeight();
1496 w = s.width; h = s.height;
1498 var x = 0, y = 0, r = Math.round;
1499 switch((anchor || "tl").toLowerCase()){
1541 var sc = this.getScroll();
1542 return [x + sc.left, y + sc.top];
1544 //Add the element's offset xy
1545 var o = this.getXY();
1546 return [x+o[0], y+o[1]];
1550 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1551 * supported position values.
1552 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1553 * @param {String} position The position to align to.
1554 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1555 * @return {Array} [x, y]
1557 getAlignToXY : function(el, p, o){
1561 throw "Element.alignTo with an element that doesn't exist";
1563 var c = false; //constrain to viewport
1564 var p1 = "", p2 = "";
1571 }else if(p.indexOf("-") == -1){
1574 p = p.toLowerCase();
1575 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1577 throw "Element.alignTo with an invalid alignment " + p;
1579 p1 = m[1]; p2 = m[2]; c = !!m[3];
1581 //Subtract the aligned el's internal xy from the target's offset xy
1582 //plus custom offset to get the aligned el's new offset xy
1583 var a1 = this.getAnchorXY(p1, true);
1584 var a2 = el.getAnchorXY(p2, false);
1585 var x = a2[0] - a1[0] + o[0];
1586 var y = a2[1] - a1[1] + o[1];
1588 //constrain the aligned el to viewport if necessary
1589 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1590 // 5px of margin for ie
1591 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1593 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1594 //perpendicular to the vp border, allow the aligned el to slide on that border,
1595 //otherwise swap the aligned el to the opposite border of the target.
1596 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1597 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1598 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1599 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1602 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1603 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1605 if((x+w) > dw + scrollX){
1606 x = swapX ? r.left-w : dw+scrollX-w;
1609 x = swapX ? r.right : scrollX;
1611 if((y+h) > dh + scrollY){
1612 y = swapY ? r.top-h : dh+scrollY-h;
1615 y = swapY ? r.bottom : scrollY;
1622 getConstrainToXY : function(){
1623 var os = {top:0, left:0, bottom:0, right: 0};
1625 return function(el, local, offsets, proposedXY){
1627 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1629 var vw, vh, vx = 0, vy = 0;
1630 if(el.dom == document.body || el.dom == document){
1631 vw = Roo.lib.Dom.getViewWidth();
1632 vh = Roo.lib.Dom.getViewHeight();
1634 vw = el.dom.clientWidth;
1635 vh = el.dom.clientHeight;
1637 var vxy = el.getXY();
1643 var s = el.getScroll();
1645 vx += offsets.left + s.left;
1646 vy += offsets.top + s.top;
1648 vw -= offsets.right;
1649 vh -= offsets.bottom;
1654 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1655 var x = xy[0], y = xy[1];
1656 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1658 // only move it if it needs it
1661 // first validate right/bottom
1670 // then make sure top/left isn't negative
1679 return moved ? [x, y] : false;
1684 adjustForConstraints : function(xy, parent, offsets){
1685 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1689 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1690 * document it aligns it to the viewport.
1691 * The position parameter is optional, and can be specified in any one of the following formats:
1693 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1694 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1695 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1696 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1697 * <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
1698 * element's anchor point, and the second value is used as the target's anchor point.</li>
1700 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1701 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1702 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1703 * that specified in order to enforce the viewport constraints.
1704 * Following are all of the supported anchor positions:
1707 ----- -----------------------------
1708 tl The top left corner (default)
1709 t The center of the top edge
1710 tr The top right corner
1711 l The center of the left edge
1712 c In the center of the element
1713 r The center of the right edge
1714 bl The bottom left corner
1715 b The center of the bottom edge
1716 br The bottom right corner
1720 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1721 el.alignTo("other-el");
1723 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1724 el.alignTo("other-el", "tr?");
1726 // align the bottom right corner of el with the center left edge of other-el
1727 el.alignTo("other-el", "br-l?");
1729 // align the center of el with the bottom left corner of other-el and
1730 // adjust the x position by -6 pixels (and the y position by 0)
1731 el.alignTo("other-el", "c-bl", [-6, 0]);
1733 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1734 * @param {String} position The position to align to.
1735 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1736 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1737 * @return {Roo.Element} this
1739 alignTo : function(element, position, offsets, animate){
1740 var xy = this.getAlignToXY(element, position, offsets);
1741 this.setXY(xy, this.preanim(arguments, 3));
1746 * Anchors an element to another element and realigns it when the window is resized.
1747 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1748 * @param {String} position The position to align to.
1749 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1750 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1751 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1752 * is a number, it is used as the buffer delay (defaults to 50ms).
1753 * @param {Function} callback The function to call after the animation finishes
1754 * @return {Roo.Element} this
1756 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1757 var action = function(){
1758 this.alignTo(el, alignment, offsets, animate);
1759 Roo.callback(callback, this);
1761 Roo.EventManager.onWindowResize(action, this);
1762 var tm = typeof monitorScroll;
1763 if(tm != 'undefined'){
1764 Roo.EventManager.on(window, 'scroll', action, this,
1765 {buffer: tm == 'number' ? monitorScroll : 50});
1767 action.call(this); // align immediately
1771 * Clears any opacity settings from this element. Required in some cases for IE.
1772 * @return {Roo.Element} this
1774 clearOpacity : function(){
1775 if (window.ActiveXObject) {
1776 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1777 this.dom.style.filter = "";
1780 this.dom.style.opacity = "";
1781 this.dom.style["-moz-opacity"] = "";
1782 this.dom.style["-khtml-opacity"] = "";
1788 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1789 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1790 * @return {Roo.Element} this
1792 hide : function(animate){
1793 this.setVisible(false, this.preanim(arguments, 0));
1798 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1799 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1800 * @return {Roo.Element} this
1802 show : function(animate){
1803 this.setVisible(true, this.preanim(arguments, 0));
1808 * @private Test if size has a unit, otherwise appends the default
1810 addUnits : function(size){
1811 return Roo.Element.addUnits(size, this.defaultUnit);
1815 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1816 * @return {Roo.Element} this
1818 beginMeasure : function(){
1820 if(el.offsetWidth || el.offsetHeight){
1821 return this; // offsets work already
1824 var p = this.dom, b = document.body; // start with this element
1825 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1826 var pe = Roo.get(p);
1827 if(pe.getStyle('display') == 'none'){
1828 changed.push({el: p, visibility: pe.getStyle("visibility")});
1829 p.style.visibility = "hidden";
1830 p.style.display = "block";
1834 this._measureChanged = changed;
1840 * Restores displays to before beginMeasure was called
1841 * @return {Roo.Element} this
1843 endMeasure : function(){
1844 var changed = this._measureChanged;
1846 for(var i = 0, len = changed.length; i < len; i++) {
1848 r.el.style.visibility = r.visibility;
1849 r.el.style.display = "none";
1851 this._measureChanged = null;
1857 * Update the innerHTML of this element, optionally searching for and processing scripts
1858 * @param {String} html The new HTML
1859 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1860 * @param {Function} callback For async script loading you can be noticed when the update completes
1861 * @return {Roo.Element} this
1863 update : function(html, loadScripts, callback){
1864 if(typeof html == "undefined"){
1867 if(loadScripts !== true){
1868 this.dom.innerHTML = html;
1869 if(typeof callback == "function"){
1877 html += '<span id="' + id + '"></span>';
1879 E.onAvailable(id, function(){
1880 var hd = document.getElementsByTagName("head")[0];
1881 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1882 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1883 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1886 while(match = re.exec(html)){
1887 var attrs = match[1];
1888 var srcMatch = attrs ? attrs.match(srcRe) : false;
1889 if(srcMatch && srcMatch[2]){
1890 var s = document.createElement("script");
1891 s.src = srcMatch[2];
1892 var typeMatch = attrs.match(typeRe);
1893 if(typeMatch && typeMatch[2]){
1894 s.type = typeMatch[2];
1897 }else if(match[2] && match[2].length > 0){
1898 if(window.execScript) {
1899 window.execScript(match[2]);
1907 window.eval(match[2]);
1911 var el = document.getElementById(id);
1912 if(el){el.parentNode.removeChild(el);}
1913 if(typeof callback == "function"){
1917 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1922 * Direct access to the UpdateManager update() method (takes the same parameters).
1923 * @param {String/Function} url The url for this request or a function to call to get the url
1924 * @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}
1925 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1926 * @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.
1927 * @return {Roo.Element} this
1930 var um = this.getUpdateManager();
1931 um.update.apply(um, arguments);
1936 * Gets this element's UpdateManager
1937 * @return {Roo.UpdateManager} The UpdateManager
1939 getUpdateManager : function(){
1940 if(!this.updateManager){
1941 this.updateManager = new Roo.UpdateManager(this);
1943 return this.updateManager;
1947 * Disables text selection for this element (normalized across browsers)
1948 * @return {Roo.Element} this
1950 unselectable : function(){
1951 this.dom.unselectable = "on";
1952 this.swallowEvent("selectstart", true);
1953 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1954 this.addClass("x-unselectable");
1959 * Calculates the x, y to center this element on the screen
1960 * @return {Array} The x, y values [x, y]
1962 getCenterXY : function(){
1963 return this.getAlignToXY(document, 'c-c');
1967 * Centers the Element in either the viewport, or another Element.
1968 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1970 center : function(centerIn){
1971 this.alignTo(centerIn || document, 'c-c');
1976 * Tests various css rules/browsers to determine if this element uses a border box
1979 isBorderBox : function(){
1980 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1984 * Return a box {x, y, width, height} that can be used to set another elements
1985 * size/location to match this element.
1986 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1987 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1988 * @return {Object} box An object in the format {x, y, width, height}
1990 getBox : function(contentBox, local){
1995 var left = parseInt(this.getStyle("left"), 10) || 0;
1996 var top = parseInt(this.getStyle("top"), 10) || 0;
1999 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
2001 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
2003 var l = this.getBorderWidth("l")+this.getPadding("l");
2004 var r = this.getBorderWidth("r")+this.getPadding("r");
2005 var t = this.getBorderWidth("t")+this.getPadding("t");
2006 var b = this.getBorderWidth("b")+this.getPadding("b");
2007 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)};
2009 bx.right = bx.x + bx.width;
2010 bx.bottom = bx.y + bx.height;
2015 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2016 for more information about the sides.
2017 * @param {String} sides
2020 getFrameWidth : function(sides, onlyContentBox){
2021 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2025 * 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.
2026 * @param {Object} box The box to fill {x, y, width, height}
2027 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2028 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2029 * @return {Roo.Element} this
2031 setBox : function(box, adjust, animate){
2032 var w = box.width, h = box.height;
2033 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2034 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2035 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2037 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2042 * Forces the browser to repaint this element
2043 * @return {Roo.Element} this
2045 repaint : function(){
2047 this.addClass("x-repaint");
2048 setTimeout(function(){
2049 Roo.get(dom).removeClass("x-repaint");
2055 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2056 * then it returns the calculated width of the sides (see getPadding)
2057 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2058 * @return {Object/Number}
2060 getMargins : function(side){
2063 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2064 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2065 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2066 right: parseInt(this.getStyle("margin-right"), 10) || 0
2069 return this.addStyles(side, El.margins);
2074 addStyles : function(sides, styles){
2076 for(var i = 0, len = sides.length; i < len; i++){
2077 v = this.getStyle(styles[sides.charAt(i)]);
2079 w = parseInt(v, 10);
2087 * Creates a proxy element of this element
2088 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2089 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2090 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2091 * @return {Roo.Element} The new proxy element
2093 createProxy : function(config, renderTo, matchBox){
2095 renderTo = Roo.getDom(renderTo);
2097 renderTo = document.body;
2099 config = typeof config == "object" ?
2100 config : {tag : "div", cls: config};
2101 var proxy = Roo.DomHelper.append(renderTo, config, true);
2103 proxy.setBox(this.getBox());
2109 * Puts a mask over this element to disable user interaction. Requires core.css.
2110 * This method can only be applied to elements which accept child nodes.
2111 * @param {String} msg (optional) A message to display in the mask
2112 * @param {String} msgCls (optional) A css class to apply to the msg element
2113 * @return {Element} The mask element
2115 mask : function(msg, msgCls)
2117 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2118 this.setStyle("position", "relative");
2121 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2123 this.addClass("x-masked");
2124 this._mask.setDisplayed(true);
2129 while (dom && dom.style) {
2130 if (!isNaN(parseInt(dom.style.zIndex))) {
2131 z = Math.max(z, parseInt(dom.style.zIndex));
2133 dom = dom.parentNode;
2135 // if we are masking the body - then it hides everything..
2136 if (this.dom == document.body) {
2138 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2139 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2142 if(typeof msg == 'string'){
2144 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2146 var mm = this._maskMsg;
2147 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2148 if (mm.dom.firstChild) { // weird IE issue?
2149 mm.dom.firstChild.innerHTML = msg;
2151 mm.setDisplayed(true);
2153 mm.setStyle('z-index', z + 102);
2155 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2156 this._mask.setHeight(this.getHeight());
2158 this._mask.setStyle('z-index', z + 100);
2164 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2165 * it is cached for reuse.
2167 unmask : function(removeEl){
2169 if(removeEl === true){
2170 this._mask.remove();
2173 this._maskMsg.remove();
2174 delete this._maskMsg;
2177 this._mask.setDisplayed(false);
2179 this._maskMsg.setDisplayed(false);
2183 this.removeClass("x-masked");
2187 * Returns true if this element is masked
2190 isMasked : function(){
2191 return this._mask && this._mask.isVisible();
2195 * Creates an iframe shim for this element to keep selects and other windowed objects from
2197 * @return {Roo.Element} The new shim element
2199 createShim : function(){
2200 var el = document.createElement('iframe');
2201 el.frameBorder = 'no';
2202 el.className = 'roo-shim';
2203 if(Roo.isIE && Roo.isSecure){
2204 el.src = Roo.SSL_SECURE_URL;
2206 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2207 shim.autoBoxAdjust = false;
2212 * Removes this element from the DOM and deletes it from the cache
2214 remove : function(){
2215 if(this.dom.parentNode){
2216 this.dom.parentNode.removeChild(this.dom);
2218 delete El.cache[this.dom.id];
2222 * Sets up event handlers to add and remove a css class when the mouse is over this element
2223 * @param {String} className
2224 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2225 * mouseout events for children elements
2226 * @return {Roo.Element} this
2228 addClassOnOver : function(className, preventFlicker){
2229 this.on("mouseover", function(){
2230 Roo.fly(this, '_internal').addClass(className);
2232 var removeFn = function(e){
2233 if(preventFlicker !== true || !e.within(this, true)){
2234 Roo.fly(this, '_internal').removeClass(className);
2237 this.on("mouseout", removeFn, this.dom);
2242 * Sets up event handlers to add and remove a css class when this element has the focus
2243 * @param {String} className
2244 * @return {Roo.Element} this
2246 addClassOnFocus : function(className){
2247 this.on("focus", function(){
2248 Roo.fly(this, '_internal').addClass(className);
2250 this.on("blur", function(){
2251 Roo.fly(this, '_internal').removeClass(className);
2256 * 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)
2257 * @param {String} className
2258 * @return {Roo.Element} this
2260 addClassOnClick : function(className){
2262 this.on("mousedown", function(){
2263 Roo.fly(dom, '_internal').addClass(className);
2264 var d = Roo.get(document);
2265 var fn = function(){
2266 Roo.fly(dom, '_internal').removeClass(className);
2267 d.removeListener("mouseup", fn);
2269 d.on("mouseup", fn);
2275 * Stops the specified event from bubbling and optionally prevents the default action
2276 * @param {String} eventName
2277 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2278 * @return {Roo.Element} this
2280 swallowEvent : function(eventName, preventDefault){
2281 var fn = function(e){
2282 e.stopPropagation();
2287 if(eventName instanceof Array){
2288 for(var i = 0, len = eventName.length; i < len; i++){
2289 this.on(eventName[i], fn);
2293 this.on(eventName, fn);
2300 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2303 * Sizes this element to its parent element's dimensions performing
2304 * neccessary box adjustments.
2305 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2306 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2307 * @return {Roo.Element} this
2309 fitToParent : function(monitorResize, targetParent) {
2310 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2311 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2312 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2315 var p = Roo.get(targetParent || this.dom.parentNode);
2316 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2317 if (monitorResize === true) {
2318 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2319 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2325 * Gets the next sibling, skipping text nodes
2326 * @return {HTMLElement} The next sibling or null
2328 getNextSibling : function(){
2329 var n = this.dom.nextSibling;
2330 while(n && n.nodeType != 1){
2337 * Gets the previous sibling, skipping text nodes
2338 * @return {HTMLElement} The previous sibling or null
2340 getPrevSibling : function(){
2341 var n = this.dom.previousSibling;
2342 while(n && n.nodeType != 1){
2343 n = n.previousSibling;
2350 * Appends the passed element(s) to this element
2351 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2352 * @return {Roo.Element} this
2354 appendChild: function(el){
2361 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2362 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2363 * automatically generated with the specified attributes.
2364 * @param {HTMLElement} insertBefore (optional) a child element of this element
2365 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2366 * @return {Roo.Element} The new child element
2368 createChild: function(config, insertBefore, returnDom){
2369 config = config || {tag:'div'};
2371 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2373 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2377 * Appends this element to the passed element
2378 * @param {String/HTMLElement/Element} el The new parent element
2379 * @return {Roo.Element} this
2381 appendTo: function(el){
2382 el = Roo.getDom(el);
2383 el.appendChild(this.dom);
2388 * Inserts this element before the passed element in the DOM
2389 * @param {String/HTMLElement/Element} el The element to insert before
2390 * @return {Roo.Element} this
2392 insertBefore: function(el){
2393 el = Roo.getDom(el);
2394 el.parentNode.insertBefore(this.dom, el);
2399 * Inserts this element after the passed element in the DOM
2400 * @param {String/HTMLElement/Element} el The element to insert after
2401 * @return {Roo.Element} this
2403 insertAfter: function(el){
2404 el = Roo.getDom(el);
2405 el.parentNode.insertBefore(this.dom, el.nextSibling);
2410 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2411 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2412 * @return {Roo.Element} The new child
2414 insertFirst: function(el, returnDom){
2416 if(typeof el == 'object' && !el.nodeType){ // dh config
2417 return this.createChild(el, this.dom.firstChild, returnDom);
2419 el = Roo.getDom(el);
2420 this.dom.insertBefore(el, this.dom.firstChild);
2421 return !returnDom ? Roo.get(el) : el;
2426 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2427 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2428 * @param {String} where (optional) 'before' or 'after' defaults to before
2429 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2430 * @return {Roo.Element} the inserted Element
2432 insertSibling: function(el, where, returnDom){
2433 where = where ? where.toLowerCase() : 'before';
2435 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2437 if(typeof el == 'object' && !el.nodeType){ // dh config
2438 if(where == 'after' && !this.dom.nextSibling){
2439 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2441 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2445 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2446 where == 'before' ? this.dom : this.dom.nextSibling);
2455 * Creates and wraps this element with another element
2456 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2457 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2458 * @return {HTMLElement/Element} The newly created wrapper element
2460 wrap: function(config, returnDom){
2462 config = {tag: "div"};
2464 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2465 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2470 * Replaces the passed element with this element
2471 * @param {String/HTMLElement/Element} el The element to replace
2472 * @return {Roo.Element} this
2474 replace: function(el){
2476 this.insertBefore(el);
2482 * Inserts an html fragment into this element
2483 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2484 * @param {String} html The HTML fragment
2485 * @param {Boolean} returnEl True to return an Roo.Element
2486 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2488 insertHtml : function(where, html, returnEl){
2489 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2490 return returnEl ? Roo.get(el) : el;
2494 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2495 * @param {Object} o The object with the attributes
2496 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2497 * @return {Roo.Element} this
2499 set : function(o, useSet){
2501 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2503 if(attr == "style" || typeof o[attr] == "function") { continue; }
2505 el.className = o["cls"];
2508 el.setAttribute(attr, o[attr]);
2515 Roo.DomHelper.applyStyles(el, o.style);
2521 * Convenience method for constructing a KeyMap
2522 * @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:
2523 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2524 * @param {Function} fn The function to call
2525 * @param {Object} scope (optional) The scope of the function
2526 * @return {Roo.KeyMap} The KeyMap created
2528 addKeyListener : function(key, fn, scope){
2530 if(typeof key != "object" || key instanceof Array){
2546 return new Roo.KeyMap(this, config);
2550 * Creates a KeyMap for this element
2551 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2552 * @return {Roo.KeyMap} The KeyMap created
2554 addKeyMap : function(config){
2555 return new Roo.KeyMap(this, config);
2559 * Returns true if this element is scrollable.
2562 isScrollable : function(){
2564 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2568 * 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().
2569 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2570 * @param {Number} value The new scroll value
2571 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2572 * @return {Element} this
2575 scrollTo : function(side, value, animate){
2576 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2578 this.dom[prop] = value;
2580 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2581 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2587 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2588 * within this element's scrollable range.
2589 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2590 * @param {Number} distance How far to scroll the element in pixels
2591 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2592 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2593 * was scrolled as far as it could go.
2595 scroll : function(direction, distance, animate){
2596 if(!this.isScrollable()){
2600 var l = el.scrollLeft, t = el.scrollTop;
2601 var w = el.scrollWidth, h = el.scrollHeight;
2602 var cw = el.clientWidth, ch = el.clientHeight;
2603 direction = direction.toLowerCase();
2604 var scrolled = false;
2605 var a = this.preanim(arguments, 2);
2610 var v = Math.min(l + distance, w-cw);
2611 this.scrollTo("left", v, a);
2618 var v = Math.max(l - distance, 0);
2619 this.scrollTo("left", v, a);
2627 var v = Math.max(t - distance, 0);
2628 this.scrollTo("top", v, a);
2636 var v = Math.min(t + distance, h-ch);
2637 this.scrollTo("top", v, a);
2646 * Translates the passed page coordinates into left/top css values for this element
2647 * @param {Number/Array} x The page x or an array containing [x, y]
2648 * @param {Number} y The page y
2649 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2651 translatePoints : function(x, y){
2652 if(typeof x == 'object' || x instanceof Array){
2655 var p = this.getStyle('position');
2656 var o = this.getXY();
2658 var l = parseInt(this.getStyle('left'), 10);
2659 var t = parseInt(this.getStyle('top'), 10);
2662 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2665 t = (p == "relative") ? 0 : this.dom.offsetTop;
2668 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2672 * Returns the current scroll position of the element.
2673 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2675 getScroll : function(){
2676 var d = this.dom, doc = document;
2677 if(d == doc || d == doc.body){
2678 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2679 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2680 return {left: l, top: t};
2682 return {left: d.scrollLeft, top: d.scrollTop};
2687 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2688 * are convert to standard 6 digit hex color.
2689 * @param {String} attr The css attribute
2690 * @param {String} defaultValue The default value to use when a valid color isn't found
2691 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2694 getColor : function(attr, defaultValue, prefix){
2695 var v = this.getStyle(attr);
2696 if(!v || v == "transparent" || v == "inherit") {
2697 return defaultValue;
2699 var color = typeof prefix == "undefined" ? "#" : prefix;
2700 if(v.substr(0, 4) == "rgb("){
2701 var rvs = v.slice(4, v.length -1).split(",");
2702 for(var i = 0; i < 3; i++){
2703 var h = parseInt(rvs[i]).toString(16);
2710 if(v.substr(0, 1) == "#"){
2712 for(var i = 1; i < 4; i++){
2713 var c = v.charAt(i);
2716 }else if(v.length == 7){
2717 color += v.substr(1);
2721 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2725 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2726 * gradient background, rounded corners and a 4-way shadow.
2727 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2728 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2729 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2730 * @return {Roo.Element} this
2732 boxWrap : function(cls){
2733 cls = cls || 'x-box';
2734 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2735 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2740 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2741 * @param {String} namespace The namespace in which to look for the attribute
2742 * @param {String} name The attribute name
2743 * @return {String} The attribute value
2745 getAttributeNS : Roo.isIE ? function(ns, name){
2747 var type = typeof d[ns+":"+name];
2748 if(type != 'undefined' && type != 'unknown'){
2749 return d[ns+":"+name];
2752 } : function(ns, name){
2754 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2759 * Sets or Returns the value the dom attribute value
2760 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2761 * @param {String} value (optional) The value to set the attribute to
2762 * @return {String} The attribute value
2764 attr : function(name){
2765 if (arguments.length > 1) {
2766 this.dom.setAttribute(name, arguments[1]);
2767 return arguments[1];
2769 if (typeof(name) == 'object') {
2770 for(var i in name) {
2771 this.attr(i, name[i]);
2777 if (!this.dom.hasAttribute(name)) {
2780 return this.dom.getAttribute(name);
2787 var ep = El.prototype;
2790 * Appends an event handler (Shorthand for addListener)
2791 * @param {String} eventName The type of event to append
2792 * @param {Function} fn The method the event invokes
2793 * @param {Object} scope (optional) The scope (this object) of the fn
2794 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2797 ep.on = ep.addListener;
2799 ep.mon = ep.addListener;
2802 * Removes an event handler from this element (shorthand for removeListener)
2803 * @param {String} eventName the type of event to remove
2804 * @param {Function} fn the method the event invokes
2805 * @return {Roo.Element} this
2808 ep.un = ep.removeListener;
2811 * true to automatically adjust width and height settings for box-model issues (default to true)
2813 ep.autoBoxAdjust = true;
2816 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2819 El.addUnits = function(v, defaultUnit){
2820 if(v === "" || v == "auto"){
2823 if(v === undefined){
2826 if(typeof v == "number" || !El.unitPattern.test(v)){
2827 return v + (defaultUnit || 'px');
2832 // special markup used throughout Roo when box wrapping elements
2833 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>';
2835 * Visibility mode constant - Use visibility to hide element
2841 * Visibility mode constant - Use display to hide element
2847 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2848 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2849 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2861 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2862 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2863 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2864 * @return {Element} The Element object
2867 El.get = function(el){
2869 if(!el){ return null; }
2870 if(typeof el == "string"){ // element id
2871 if(!(elm = document.getElementById(el))){
2874 if(ex = El.cache[el]){
2877 ex = El.cache[el] = new El(elm);
2880 }else if(el.tagName){ // dom element
2884 if(ex = El.cache[id]){
2887 ex = El.cache[id] = new El(el);
2890 }else if(el instanceof El){
2892 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2893 // catch case where it hasn't been appended
2894 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2897 }else if(el.isComposite){
2899 }else if(el instanceof Array){
2900 return El.select(el);
2901 }else if(el == document){
2902 // create a bogus element object representing the document object
2904 var f = function(){};
2905 f.prototype = El.prototype;
2907 docEl.dom = document;
2915 El.uncache = function(el){
2916 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2918 delete El.cache[a[i].id || a[i]];
2924 // Garbage collection - uncache elements/purge listeners on orphaned elements
2925 // so we don't hold a reference and cause the browser to retain them
2926 El.garbageCollect = function(){
2927 if(!Roo.enableGarbageCollector){
2928 clearInterval(El.collectorThread);
2931 for(var eid in El.cache){
2932 var el = El.cache[eid], d = el.dom;
2933 // -------------------------------------------------------
2934 // Determining what is garbage:
2935 // -------------------------------------------------------
2937 // dom node is null, definitely garbage
2938 // -------------------------------------------------------
2940 // no parentNode == direct orphan, definitely garbage
2941 // -------------------------------------------------------
2942 // !d.offsetParent && !document.getElementById(eid)
2943 // display none elements have no offsetParent so we will
2944 // also try to look it up by it's id. However, check
2945 // offsetParent first so we don't do unneeded lookups.
2946 // This enables collection of elements that are not orphans
2947 // directly, but somewhere up the line they have an orphan
2949 // -------------------------------------------------------
2950 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2951 delete El.cache[eid];
2952 if(d && Roo.enableListenerCollection){
2958 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2962 El.Flyweight = function(dom){
2965 El.Flyweight.prototype = El.prototype;
2967 El._flyweights = {};
2969 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2970 * the dom node can be overwritten by other code.
2971 * @param {String/HTMLElement} el The dom node or id
2972 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2973 * prevent conflicts (e.g. internally Roo uses "_internal")
2975 * @return {Element} The shared Element object
2977 El.fly = function(el, named){
2978 named = named || '_global';
2979 el = Roo.getDom(el);
2983 if(!El._flyweights[named]){
2984 El._flyweights[named] = new El.Flyweight();
2986 El._flyweights[named].dom = el;
2987 return El._flyweights[named];
2991 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2992 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2993 * Shorthand of {@link Roo.Element#get}
2994 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2995 * @return {Element} The Element object
3001 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3002 * the dom node can be overwritten by other code.
3003 * Shorthand of {@link Roo.Element#fly}
3004 * @param {String/HTMLElement} el The dom node or id
3005 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3006 * prevent conflicts (e.g. internally Roo uses "_internal")
3008 * @return {Element} The shared Element object
3014 // speedy lookup for elements never to box adjust
3015 var noBoxAdjust = Roo.isStrict ? {
3018 input:1, select:1, textarea:1
3020 if(Roo.isIE || Roo.isGecko){
3021 noBoxAdjust['button'] = 1;
3025 Roo.EventManager.on(window, 'unload', function(){
3027 delete El._flyweights;
3035 Roo.Element.selectorFunction = Roo.DomQuery.select;
3038 Roo.Element.select = function(selector, unique, root){
3040 if(typeof selector == "string"){
3041 els = Roo.Element.selectorFunction(selector, root);
3042 }else if(selector.length !== undefined){
3045 throw "Invalid selector";
3047 if(unique === true){
3048 return new Roo.CompositeElement(els);
3050 return new Roo.CompositeElementLite(els);
3054 * Selects elements based on the passed CSS selector to enable working on them as 1.
3055 * @param {String/Array} selector The CSS selector or an array of elements
3056 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3057 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3058 * @return {CompositeElementLite/CompositeElement}
3062 Roo.select = Roo.Element.select;