4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
13 // was in Composite Element!??!?!
17 var E = Roo.lib.Event;
20 // local style camelizing for speed
22 var camelRe = /(-[a-z])/gi;
23 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
24 var view = document.defaultView;
28 * Represents an Element in the DOM.<br><br>
31 var el = Roo.get("my-div");
34 var el = getEl("my-div");
36 // or with a DOM element
37 var el = Roo.get(myDivElement);
39 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
40 * each call instead of constructing a new one.<br><br>
41 * <b>Animations</b><br />
42 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
43 * should either be a boolean (true) or an object literal with animation options. The animation options are:
45 Option Default Description
46 --------- -------- ---------------------------------------------
47 duration .35 The duration of the animation in seconds
48 easing easeOut The YUI easing method
49 callback none A function to execute when the anim completes
50 scope this The scope (this) of the callback function
52 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
53 * manipulate the animation. Here's an example:
55 var el = Roo.get("my-div");
61 el.setWidth(100, true);
63 // animation with some options set
70 // using the "anim" property to get the Anim object
76 el.setWidth(100, opt);
78 if(opt.anim.isAnimated()){
82 * <b> Composite (Collections of) Elements</b><br />
83 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
84 * @constructor Create a new Element directly.
85 * @param {String/HTMLElement} element
86 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
88 Roo.Element = function(element, forceNew){
89 var dom = typeof element == "string" ?
90 document.getElementById(element) : element;
91 if(!dom){ // invalid id/element
95 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
96 return Roo.Element.cache[id];
109 this.id = id || Roo.id(dom);
112 var El = Roo.Element;
116 * The element's default display mode (defaults to "")
119 originalDisplay : "",
123 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
129 * Sets the element's visibility mode. When setVisible() is called it
130 * will use this to determine whether to set the visibility or the display property.
131 * @param visMode Element.VISIBILITY or Element.DISPLAY
132 * @return {Roo.Element} this
134 setVisibilityMode : function(visMode){
135 this.visibilityMode = visMode;
139 * Convenience method for setVisibilityMode(Element.DISPLAY)
140 * @param {String} display (optional) What to set display to when visible
141 * @return {Roo.Element} this
143 enableDisplayMode : function(display){
144 this.setVisibilityMode(El.DISPLAY);
145 if(typeof display != "undefined") { this.originalDisplay = display; }
150 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
151 * @param {String} selector The simple selector to test
152 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
153 search as a number or element (defaults to 10 || document.body)
154 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
155 * @return {HTMLElement} The matching DOM node (or null if no match was found)
157 findParent : function(simpleSelector, maxDepth, returnEl){
158 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
159 maxDepth = maxDepth || 50;
160 if(typeof maxDepth != "number"){
161 stopEl = Roo.getDom(maxDepth);
164 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
165 if(dq.is(p, simpleSelector)){
166 return returnEl ? Roo.get(p) : p;
176 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
177 * @param {String} selector The simple selector to test
178 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
179 search as a number or element (defaults to 10 || document.body)
180 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
181 * @return {HTMLElement} The matching DOM node (or null if no match was found)
183 findParentNode : function(simpleSelector, maxDepth, returnEl){
184 var p = Roo.fly(this.dom.parentNode, '_internal');
185 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
189 * Looks at the scrollable parent element
191 findScrollableParent : function()
193 var overflowRegex = /(auto|scroll)/;
195 if(this.getStyle('position') === 'fixed'){
196 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
199 var excludeStaticParent = this.getStyle('position') === "absolute";
201 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
203 if (excludeStaticParent && parent.getStyle('position') === "static") {
207 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
211 if(parent.dom.nodeName.toLowerCase() == 'body'){
213 alert('is android : ' + Roo.isAndroid);
214 alert('is ios : ' + Roo.isIOS);
218 return Roo.get(document.documentElement);
222 alert('not android');
225 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
229 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
233 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
234 * This is a shortcut for findParentNode() that always returns an Roo.Element.
235 * @param {String} selector The simple selector to test
236 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
237 search as a number or element (defaults to 10 || document.body)
238 * @return {Roo.Element} The matching DOM node (or null if no match was found)
240 up : function(simpleSelector, maxDepth){
241 return this.findParentNode(simpleSelector, maxDepth, true);
247 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
248 * @param {String} selector The simple selector to test
249 * @return {Boolean} True if this element matches the selector, else false
251 is : function(simpleSelector){
252 return Roo.DomQuery.is(this.dom, simpleSelector);
256 * Perform animation on this element.
257 * @param {Object} args The YUI animation control args
258 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
259 * @param {Function} onComplete (optional) Function to call when animation completes
260 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
261 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
262 * @return {Roo.Element} this
264 animate : function(args, duration, onComplete, easing, animType){
265 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
270 * @private Internal animation call
272 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
273 animType = animType || 'run';
275 var anim = Roo.lib.Anim[animType](
277 (opt.duration || defaultDur) || .35,
278 (opt.easing || defaultEase) || 'easeOut',
280 Roo.callback(cb, this);
281 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
289 // private legacy anim prep
290 preanim : function(a, i){
291 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
295 * Removes worthless text nodes
296 * @param {Boolean} forceReclean (optional) By default the element
297 * keeps track if it has been cleaned already so
298 * you can call this over and over. However, if you update the element and
299 * need to force a reclean, you can pass true.
301 clean : function(forceReclean){
302 if(this.isCleaned && forceReclean !== true){
306 var d = this.dom, n = d.firstChild, ni = -1;
308 var nx = n.nextSibling;
309 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
316 this.isCleaned = true;
321 calcOffsetsTo : function(el){
324 var restorePos = false;
325 if(el.getStyle('position') == 'static'){
326 el.position('relative');
331 while(op && op != d && op.tagName != 'HTML'){
334 op = op.offsetParent;
337 el.position('static');
343 * Scrolls this element into view within the passed container.
344 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
345 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
346 * @return {Roo.Element} this
348 scrollIntoView : function(container, hscroll){
349 var c = Roo.getDom(container) || document.body;
352 var o = this.calcOffsetsTo(c),
355 b = t+el.offsetHeight,
356 r = l+el.offsetWidth;
358 var ch = c.clientHeight;
359 var ct = parseInt(c.scrollTop, 10);
360 var cl = parseInt(c.scrollLeft, 10);
362 var cr = cl + c.clientWidth;
370 if(hscroll !== false){
374 c.scrollLeft = r-c.clientWidth;
381 scrollChildIntoView : function(child, hscroll){
382 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
386 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
387 * the new height may not be available immediately.
388 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
389 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
390 * @param {Function} onComplete (optional) Function to call when animation completes
391 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
392 * @return {Roo.Element} this
394 autoHeight : function(animate, duration, onComplete, easing){
395 var oldHeight = this.getHeight();
397 this.setHeight(1); // force clipping
398 setTimeout(function(){
399 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
401 this.setHeight(height);
403 if(typeof onComplete == "function"){
407 this.setHeight(oldHeight); // restore original height
408 this.setHeight(height, animate, duration, function(){
410 if(typeof onComplete == "function") { onComplete(); }
411 }.createDelegate(this), easing);
413 }.createDelegate(this), 0);
418 * Returns true if this element is an ancestor of the passed element
419 * @param {HTMLElement/String} el The element to check
420 * @return {Boolean} True if this element is an ancestor of el, else false
422 contains : function(el){
423 if(!el){return false;}
424 return D.isAncestor(this.dom, el.dom ? el.dom : el);
428 * Checks whether the element is currently visible using both visibility and display properties.
429 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
430 * @return {Boolean} True if the element is currently visible, else false
432 isVisible : function(deep) {
433 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
434 if(deep !== true || !vis){
437 var p = this.dom.parentNode;
438 while(p && p.tagName.toLowerCase() != "body"){
439 if(!Roo.fly(p, '_isVisible').isVisible()){
448 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
449 * @param {String} selector The CSS selector
450 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
451 * @return {CompositeElement/CompositeElementLite} The composite element
453 select : function(selector, unique){
454 return El.select(selector, unique, this.dom);
458 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
459 * @param {String} selector The CSS selector
460 * @return {Array} An array of the matched nodes
462 query : function(selector, unique){
463 return Roo.DomQuery.select(selector, this.dom);
467 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
468 * @param {String} selector The CSS selector
469 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
470 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
472 child : function(selector, returnDom){
473 var n = Roo.DomQuery.selectNode(selector, this.dom);
474 return returnDom ? n : Roo.get(n);
478 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
479 * @param {String} selector The CSS selector
480 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
481 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
483 down : function(selector, returnDom){
484 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
485 return returnDom ? n : Roo.get(n);
489 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
490 * @param {String} group The group the DD object is member of
491 * @param {Object} config The DD config object
492 * @param {Object} overrides An object containing methods to override/implement on the DD object
493 * @return {Roo.dd.DD} The DD object
495 initDD : function(group, config, overrides){
496 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
497 return Roo.apply(dd, overrides);
501 * Initializes a {@link Roo.dd.DDProxy} object for this element.
502 * @param {String} group The group the DDProxy object is member of
503 * @param {Object} config The DDProxy config object
504 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
505 * @return {Roo.dd.DDProxy} The DDProxy object
507 initDDProxy : function(group, config, overrides){
508 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
509 return Roo.apply(dd, overrides);
513 * Initializes a {@link Roo.dd.DDTarget} object for this element.
514 * @param {String} group The group the DDTarget object is member of
515 * @param {Object} config The DDTarget config object
516 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
517 * @return {Roo.dd.DDTarget} The DDTarget object
519 initDDTarget : function(group, config, overrides){
520 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
521 return Roo.apply(dd, overrides);
525 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
526 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
527 * @param {Boolean} visible Whether the element is visible
528 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
529 * @return {Roo.Element} this
531 setVisible : function(visible, animate){
533 if(this.visibilityMode == El.DISPLAY){
534 this.setDisplayed(visible);
537 this.dom.style.visibility = visible ? "visible" : "hidden";
540 // closure for composites
542 var visMode = this.visibilityMode;
544 this.setOpacity(.01);
545 this.setVisible(true);
547 this.anim({opacity: { to: (visible?1:0) }},
548 this.preanim(arguments, 1),
549 null, .35, 'easeIn', function(){
551 if(visMode == El.DISPLAY){
552 dom.style.display = "none";
554 dom.style.visibility = "hidden";
556 Roo.get(dom).setOpacity(1);
564 * Returns true if display is not "none"
567 isDisplayed : function() {
568 return this.getStyle("display") != "none";
572 * Toggles the element's visibility or display, depending on visibility mode.
573 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
574 * @return {Roo.Element} this
576 toggle : function(animate){
577 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
582 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
583 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
584 * @return {Roo.Element} this
586 setDisplayed : function(value) {
587 if(typeof value == "boolean"){
588 value = value ? this.originalDisplay : "none";
590 this.setStyle("display", value);
595 * Tries to focus the element. Any exceptions are caught and ignored.
596 * @return {Roo.Element} this
606 * Tries to blur the element. Any exceptions are caught and ignored.
607 * @return {Roo.Element} this
617 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
618 * @param {String/Array} className The CSS class to add, or an array of classes
619 * @return {Roo.Element} this
621 addClass : function(className){
622 if(className instanceof Array){
623 for(var i = 0, len = className.length; i < len; i++) {
624 this.addClass(className[i]);
627 if(className && !this.hasClass(className)){
628 this.dom.className = this.dom.className + " " + className;
635 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
636 * @param {String/Array} className The CSS class to add, or an array of classes
637 * @return {Roo.Element} this
639 radioClass : function(className){
640 var siblings = this.dom.parentNode.childNodes;
641 for(var i = 0; i < siblings.length; i++) {
644 Roo.get(s).removeClass(className);
647 this.addClass(className);
652 * Removes one or more CSS classes from the element.
653 * @param {String/Array} className The CSS class to remove, or an array of classes
654 * @return {Roo.Element} this
656 removeClass : function(className){
657 if(!className || !this.dom.className){
660 if(className instanceof Array){
661 for(var i = 0, len = className.length; i < len; i++) {
662 this.removeClass(className[i]);
665 if(this.hasClass(className)){
666 var re = this.classReCache[className];
668 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
669 this.classReCache[className] = re;
672 this.dom.className.replace(re, " ");
682 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
683 * @param {String} className The CSS class to toggle
684 * @return {Roo.Element} this
686 toggleClass : function(className){
687 if(this.hasClass(className)){
688 this.removeClass(className);
690 this.addClass(className);
696 * Checks if the specified CSS class exists on this element's DOM node.
697 * @param {String} className The CSS class to check for
698 * @return {Boolean} True if the class exists, else false
700 hasClass : function(className){
701 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
705 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
706 * @param {String} oldClassName The CSS class to replace
707 * @param {String} newClassName The replacement CSS class
708 * @return {Roo.Element} this
710 replaceClass : function(oldClassName, newClassName){
711 this.removeClass(oldClassName);
712 this.addClass(newClassName);
717 * Returns an object with properties matching the styles requested.
718 * For example, el.getStyles('color', 'font-size', 'width') might return
719 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
720 * @param {String} style1 A style name
721 * @param {String} style2 A style name
722 * @param {String} etc.
723 * @return {Object} The style object
725 getStyles : function(){
726 var a = arguments, len = a.length, r = {};
727 for(var i = 0; i < len; i++){
728 r[a[i]] = this.getStyle(a[i]);
734 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
735 * @param {String} property The style property whose value is returned.
736 * @return {String} The current value of the style property for this element.
738 getStyle : function(){
739 return view && view.getComputedStyle ?
741 var el = this.dom, v, cs, camel;
745 if(el.style && (v = el.style[prop])){
748 if(cs = view.getComputedStyle(el, "")){
749 if(!(camel = propCache[prop])){
750 camel = propCache[prop] = prop.replace(camelRe, camelFn);
757 var el = this.dom, v, cs, camel;
758 if(prop == 'opacity'){
759 if(typeof el.style.filter == 'string'){
760 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
762 var fv = parseFloat(m[1]);
764 return fv ? fv / 100 : 0;
769 }else if(prop == 'float'){
772 if(!(camel = propCache[prop])){
773 camel = propCache[prop] = prop.replace(camelRe, camelFn);
775 if(v = el.style[camel]){
778 if(cs = el.currentStyle){
786 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
787 * @param {String/Object} property The style property to be set, or an object of multiple styles.
788 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
789 * @return {Roo.Element} this
791 setStyle : function(prop, value){
792 if(typeof prop == "string"){
794 if (prop == 'float') {
795 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
800 if(!(camel = propCache[prop])){
801 camel = propCache[prop] = prop.replace(camelRe, camelFn);
804 if(camel == 'opacity') {
805 this.setOpacity(value);
807 this.dom.style[camel] = value;
810 for(var style in prop){
811 if(typeof prop[style] != "function"){
812 this.setStyle(style, prop[style]);
820 * More flexible version of {@link #setStyle} for setting style properties.
821 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
822 * a function which returns such a specification.
823 * @return {Roo.Element} this
825 applyStyles : function(style){
826 Roo.DomHelper.applyStyles(this.dom, style);
831 * 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).
832 * @return {Number} The X position of the element
835 return D.getX(this.dom);
839 * 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).
840 * @return {Number} The Y position of the element
843 return D.getY(this.dom);
847 * 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).
848 * @return {Array} The XY position of the element
851 return D.getXY(this.dom);
855 * 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).
856 * @param {Number} The X position of the element
857 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
858 * @return {Roo.Element} this
860 setX : function(x, animate){
864 this.setXY([x, this.getY()], this.preanim(arguments, 1));
870 * 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).
871 * @param {Number} The Y position of the element
872 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
873 * @return {Roo.Element} this
875 setY : function(y, animate){
879 this.setXY([this.getX(), y], this.preanim(arguments, 1));
885 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
886 * @param {String} left The left CSS property value
887 * @return {Roo.Element} this
889 setLeft : function(left){
890 this.setStyle("left", this.addUnits(left));
895 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
896 * @param {String} top The top CSS property value
897 * @return {Roo.Element} this
899 setTop : function(top){
900 this.setStyle("top", this.addUnits(top));
905 * Sets the element's CSS right style.
906 * @param {String} right The right CSS property value
907 * @return {Roo.Element} this
909 setRight : function(right){
910 this.setStyle("right", this.addUnits(right));
915 * Sets the element's CSS bottom style.
916 * @param {String} bottom The bottom CSS property value
917 * @return {Roo.Element} this
919 setBottom : function(bottom){
920 this.setStyle("bottom", this.addUnits(bottom));
925 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
926 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
927 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
928 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
929 * @return {Roo.Element} this
931 setXY : function(pos, animate){
933 D.setXY(this.dom, pos);
935 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
941 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
942 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
943 * @param {Number} x X value for new position (coordinates are page-based)
944 * @param {Number} y Y value for new position (coordinates are page-based)
945 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
946 * @return {Roo.Element} this
948 setLocation : function(x, y, animate){
949 this.setXY([x, y], this.preanim(arguments, 2));
954 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
955 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
956 * @param {Number} x X value for new position (coordinates are page-based)
957 * @param {Number} y Y value for new position (coordinates are page-based)
958 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
959 * @return {Roo.Element} this
961 moveTo : function(x, y, animate){
962 this.setXY([x, y], this.preanim(arguments, 2));
967 * Returns the region of the given element.
968 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
969 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
971 getRegion : function(){
972 return D.getRegion(this.dom);
976 * Returns the offset height of the element
977 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
978 * @return {Number} The element's height
980 getHeight : function(contentHeight){
981 var h = this.dom.offsetHeight || 0;
982 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
986 * Returns the offset width of the element
987 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
988 * @return {Number} The element's width
990 getWidth : function(contentWidth){
991 var w = this.dom.offsetWidth || 0;
992 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
996 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
997 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
998 * if a height has not been set using CSS.
1001 getComputedHeight : function(){
1002 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
1004 h = parseInt(this.getStyle('height'), 10) || 0;
1005 if(!this.isBorderBox()){
1006 h += this.getFrameWidth('tb');
1013 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1014 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1015 * if a width has not been set using CSS.
1018 getComputedWidth : function(){
1019 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1021 w = parseInt(this.getStyle('width'), 10) || 0;
1022 if(!this.isBorderBox()){
1023 w += this.getFrameWidth('lr');
1030 * Returns the size of the element.
1031 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1032 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1034 getSize : function(contentSize){
1035 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1039 * Returns the width and height of the viewport.
1040 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1042 getViewSize : function(){
1043 var d = this.dom, doc = document, aw = 0, ah = 0;
1044 if(d == doc || d == doc.body){
1045 return {width : D.getViewWidth(), height: D.getViewHeight()};
1048 width : d.clientWidth,
1049 height: d.clientHeight
1055 * Returns the value of the "value" attribute
1056 * @param {Boolean} asNumber true to parse the value as a number
1057 * @return {String/Number}
1059 getValue : function(asNumber){
1060 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1064 adjustWidth : function(width){
1065 if(typeof width == "number"){
1066 if(this.autoBoxAdjust && !this.isBorderBox()){
1067 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1077 adjustHeight : function(height){
1078 if(typeof height == "number"){
1079 if(this.autoBoxAdjust && !this.isBorderBox()){
1080 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1090 * Set the width of the element
1091 * @param {Number} width The new width
1092 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1093 * @return {Roo.Element} this
1095 setWidth : function(width, animate){
1096 width = this.adjustWidth(width);
1098 this.dom.style.width = this.addUnits(width);
1100 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1106 * Set the height of the element
1107 * @param {Number} height The new height
1108 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1109 * @return {Roo.Element} this
1111 setHeight : function(height, animate){
1112 height = this.adjustHeight(height);
1114 this.dom.style.height = this.addUnits(height);
1116 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1122 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1123 * @param {Number} width The new width
1124 * @param {Number} height The new height
1125 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1126 * @return {Roo.Element} this
1128 setSize : function(width, height, animate){
1129 if(typeof width == "object"){ // in case of object from getSize()
1130 height = width.height; width = width.width;
1132 width = this.adjustWidth(width); height = this.adjustHeight(height);
1134 this.dom.style.width = this.addUnits(width);
1135 this.dom.style.height = this.addUnits(height);
1137 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1143 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1144 * @param {Number} x X value for new position (coordinates are page-based)
1145 * @param {Number} y Y value for new position (coordinates are page-based)
1146 * @param {Number} width The new width
1147 * @param {Number} height The new height
1148 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1149 * @return {Roo.Element} this
1151 setBounds : function(x, y, width, height, animate){
1153 this.setSize(width, height);
1154 this.setLocation(x, y);
1156 width = this.adjustWidth(width); height = this.adjustHeight(height);
1157 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1158 this.preanim(arguments, 4), 'motion');
1164 * 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.
1165 * @param {Roo.lib.Region} region The region to fill
1166 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1167 * @return {Roo.Element} this
1169 setRegion : function(region, animate){
1170 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1175 * Appends an event handler
1177 * @param {String} eventName The type of event to append
1178 * @param {Function} fn The method the event invokes
1179 * @param {Object} scope (optional) The scope (this object) of the fn
1180 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1182 addListener : function(eventName, fn, scope, options){
1184 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1189 * Removes an event handler from this element
1190 * @param {String} eventName the type of event to remove
1191 * @param {Function} fn the method the event invokes
1192 * @return {Roo.Element} this
1194 removeListener : function(eventName, fn){
1195 Roo.EventManager.removeListener(this.dom, eventName, fn);
1200 * Removes all previous added listeners from this element
1201 * @return {Roo.Element} this
1203 removeAllListeners : function(){
1204 E.purgeElement(this.dom);
1208 relayEvent : function(eventName, observable){
1209 this.on(eventName, function(e){
1210 observable.fireEvent(eventName, e);
1215 * Set the opacity of the element
1216 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1217 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1218 * @return {Roo.Element} this
1220 setOpacity : function(opacity, animate){
1222 var s = this.dom.style;
1225 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1226 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1228 s.opacity = opacity;
1231 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1237 * Gets the left X coordinate
1238 * @param {Boolean} local True to get the local css position instead of page coordinate
1241 getLeft : function(local){
1245 return parseInt(this.getStyle("left"), 10) || 0;
1250 * Gets the right X coordinate of the element (element X position + element width)
1251 * @param {Boolean} local True to get the local css position instead of page coordinate
1254 getRight : function(local){
1256 return this.getX() + this.getWidth();
1258 return (this.getLeft(true) + this.getWidth()) || 0;
1263 * Gets the top Y coordinate
1264 * @param {Boolean} local True to get the local css position instead of page coordinate
1267 getTop : function(local) {
1271 return parseInt(this.getStyle("top"), 10) || 0;
1276 * Gets the bottom Y coordinate of the element (element Y position + element height)
1277 * @param {Boolean} local True to get the local css position instead of page coordinate
1280 getBottom : function(local){
1282 return this.getY() + this.getHeight();
1284 return (this.getTop(true) + this.getHeight()) || 0;
1289 * Initializes positioning on this element. If a desired position is not passed, it will make the
1290 * the element positioned relative IF it is not already positioned.
1291 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1292 * @param {Number} zIndex (optional) The zIndex to apply
1293 * @param {Number} x (optional) Set the page X position
1294 * @param {Number} y (optional) Set the page Y position
1296 position : function(pos, zIndex, x, y){
1298 if(this.getStyle('position') == 'static'){
1299 this.setStyle('position', 'relative');
1302 this.setStyle("position", pos);
1305 this.setStyle("z-index", zIndex);
1307 if(x !== undefined && y !== undefined){
1309 }else if(x !== undefined){
1311 }else if(y !== undefined){
1317 * Clear positioning back to the default when the document was loaded
1318 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1319 * @return {Roo.Element} this
1321 clearPositioning : function(value){
1329 "position" : "static"
1335 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1336 * snapshot before performing an update and then restoring the element.
1339 getPositioning : function(){
1340 var l = this.getStyle("left");
1341 var t = this.getStyle("top");
1343 "position" : this.getStyle("position"),
1345 "right" : l ? "" : this.getStyle("right"),
1347 "bottom" : t ? "" : this.getStyle("bottom"),
1348 "z-index" : this.getStyle("z-index")
1353 * Gets the width of the border(s) for the specified side(s)
1354 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1355 * passing lr would get the border (l)eft width + the border (r)ight width.
1356 * @return {Number} The width of the sides passed added together
1358 getBorderWidth : function(side){
1359 return this.addStyles(side, El.borders);
1363 * Gets the width of the padding(s) for the specified side(s)
1364 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1365 * passing lr would get the padding (l)eft + the padding (r)ight.
1366 * @return {Number} The padding of the sides passed added together
1368 getPadding : function(side){
1369 return this.addStyles(side, El.paddings);
1373 * Set positioning with an object returned by getPositioning().
1374 * @param {Object} posCfg
1375 * @return {Roo.Element} this
1377 setPositioning : function(pc){
1378 this.applyStyles(pc);
1379 if(pc.right == "auto"){
1380 this.dom.style.right = "";
1382 if(pc.bottom == "auto"){
1383 this.dom.style.bottom = "";
1389 fixDisplay : function(){
1390 if(this.getStyle("display") == "none"){
1391 this.setStyle("visibility", "hidden");
1392 this.setStyle("display", this.originalDisplay); // first try reverting to default
1393 if(this.getStyle("display") == "none"){ // if that fails, default to block
1394 this.setStyle("display", "block");
1400 * Quick set left and top adding default units
1401 * @param {String} left The left CSS property value
1402 * @param {String} top The top CSS property value
1403 * @return {Roo.Element} this
1405 setLeftTop : function(left, top){
1406 this.dom.style.left = this.addUnits(left);
1407 this.dom.style.top = this.addUnits(top);
1412 * Move this element relative to its current position.
1413 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1414 * @param {Number} distance How far to move the element in pixels
1415 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1416 * @return {Roo.Element} this
1418 move : function(direction, distance, animate){
1419 var xy = this.getXY();
1420 direction = direction.toLowerCase();
1424 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1428 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1433 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1438 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1445 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1446 * @return {Roo.Element} this
1449 if(!this.isClipped){
1450 this.isClipped = true;
1451 this.originalClip = {
1452 "o": this.getStyle("overflow"),
1453 "x": this.getStyle("overflow-x"),
1454 "y": this.getStyle("overflow-y")
1456 this.setStyle("overflow", "hidden");
1457 this.setStyle("overflow-x", "hidden");
1458 this.setStyle("overflow-y", "hidden");
1464 * Return clipping (overflow) to original clipping before clip() was called
1465 * @return {Roo.Element} this
1467 unclip : function(){
1469 this.isClipped = false;
1470 var o = this.originalClip;
1471 if(o.o){this.setStyle("overflow", o.o);}
1472 if(o.x){this.setStyle("overflow-x", o.x);}
1473 if(o.y){this.setStyle("overflow-y", o.y);}
1480 * Gets the x,y coordinates specified by the anchor position on the element.
1481 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1482 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1483 * {width: (target width), height: (target height)} (defaults to the element's current size)
1484 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1485 * @return {Array} [x, y] An array containing the element's x and y coordinates
1487 getAnchorXY : function(anchor, local, s){
1488 //Passing a different size is useful for pre-calculating anchors,
1489 //especially for anchored animations that change the el size.
1491 var w, h, vp = false;
1494 if(d == document.body || d == document){
1496 w = D.getViewWidth(); h = D.getViewHeight();
1498 w = this.getWidth(); h = this.getHeight();
1501 w = s.width; h = s.height;
1503 var x = 0, y = 0, r = Math.round;
1504 switch((anchor || "tl").toLowerCase()){
1546 var sc = this.getScroll();
1547 return [x + sc.left, y + sc.top];
1549 //Add the element's offset xy
1550 var o = this.getXY();
1551 return [x+o[0], y+o[1]];
1555 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1556 * supported position values.
1557 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1558 * @param {String} position The position to align to.
1559 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1560 * @return {Array} [x, y]
1562 getAlignToXY : function(el, p, o){
1566 throw "Element.alignTo with an element that doesn't exist";
1568 var c = false; //constrain to viewport
1569 var p1 = "", p2 = "";
1576 }else if(p.indexOf("-") == -1){
1579 p = p.toLowerCase();
1580 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1582 throw "Element.alignTo with an invalid alignment " + p;
1584 p1 = m[1]; p2 = m[2]; c = !!m[3];
1586 //Subtract the aligned el's internal xy from the target's offset xy
1587 //plus custom offset to get the aligned el's new offset xy
1588 var a1 = this.getAnchorXY(p1, true);
1589 var a2 = el.getAnchorXY(p2, false);
1590 var x = a2[0] - a1[0] + o[0];
1591 var y = a2[1] - a1[1] + o[1];
1593 //constrain the aligned el to viewport if necessary
1594 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1595 // 5px of margin for ie
1596 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1598 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1599 //perpendicular to the vp border, allow the aligned el to slide on that border,
1600 //otherwise swap the aligned el to the opposite border of the target.
1601 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1602 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1603 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1604 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1607 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1608 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1610 if((x+w) > dw + scrollX){
1611 x = swapX ? r.left-w : dw+scrollX-w;
1614 x = swapX ? r.right : scrollX;
1616 if((y+h) > dh + scrollY){
1617 y = swapY ? r.top-h : dh+scrollY-h;
1620 y = swapY ? r.bottom : scrollY;
1627 getConstrainToXY : function(){
1628 var os = {top:0, left:0, bottom:0, right: 0};
1630 return function(el, local, offsets, proposedXY){
1632 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1634 var vw, vh, vx = 0, vy = 0;
1635 if(el.dom == document.body || el.dom == document){
1636 vw = Roo.lib.Dom.getViewWidth();
1637 vh = Roo.lib.Dom.getViewHeight();
1639 vw = el.dom.clientWidth;
1640 vh = el.dom.clientHeight;
1642 var vxy = el.getXY();
1648 var s = el.getScroll();
1650 vx += offsets.left + s.left;
1651 vy += offsets.top + s.top;
1653 vw -= offsets.right;
1654 vh -= offsets.bottom;
1659 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1660 var x = xy[0], y = xy[1];
1661 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1663 // only move it if it needs it
1666 // first validate right/bottom
1675 // then make sure top/left isn't negative
1684 return moved ? [x, y] : false;
1689 adjustForConstraints : function(xy, parent, offsets){
1690 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1694 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1695 * document it aligns it to the viewport.
1696 * The position parameter is optional, and can be specified in any one of the following formats:
1698 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1699 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1700 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1701 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1702 * <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
1703 * element's anchor point, and the second value is used as the target's anchor point.</li>
1705 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1706 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1707 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1708 * that specified in order to enforce the viewport constraints.
1709 * Following are all of the supported anchor positions:
1712 ----- -----------------------------
1713 tl The top left corner (default)
1714 t The center of the top edge
1715 tr The top right corner
1716 l The center of the left edge
1717 c In the center of the element
1718 r The center of the right edge
1719 bl The bottom left corner
1720 b The center of the bottom edge
1721 br The bottom right corner
1725 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1726 el.alignTo("other-el");
1728 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1729 el.alignTo("other-el", "tr?");
1731 // align the bottom right corner of el with the center left edge of other-el
1732 el.alignTo("other-el", "br-l?");
1734 // align the center of el with the bottom left corner of other-el and
1735 // adjust the x position by -6 pixels (and the y position by 0)
1736 el.alignTo("other-el", "c-bl", [-6, 0]);
1738 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1739 * @param {String} position The position to align to.
1740 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1741 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1742 * @return {Roo.Element} this
1744 alignTo : function(element, position, offsets, animate){
1745 var xy = this.getAlignToXY(element, position, offsets);
1746 this.setXY(xy, this.preanim(arguments, 3));
1751 * Anchors an element to another element and realigns it when the window is resized.
1752 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1753 * @param {String} position The position to align to.
1754 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1755 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1756 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1757 * is a number, it is used as the buffer delay (defaults to 50ms).
1758 * @param {Function} callback The function to call after the animation finishes
1759 * @return {Roo.Element} this
1761 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1762 var action = function(){
1763 this.alignTo(el, alignment, offsets, animate);
1764 Roo.callback(callback, this);
1766 Roo.EventManager.onWindowResize(action, this);
1767 var tm = typeof monitorScroll;
1768 if(tm != 'undefined'){
1769 Roo.EventManager.on(window, 'scroll', action, this,
1770 {buffer: tm == 'number' ? monitorScroll : 50});
1772 action.call(this); // align immediately
1776 * Clears any opacity settings from this element. Required in some cases for IE.
1777 * @return {Roo.Element} this
1779 clearOpacity : function(){
1780 if (window.ActiveXObject) {
1781 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1782 this.dom.style.filter = "";
1785 this.dom.style.opacity = "";
1786 this.dom.style["-moz-opacity"] = "";
1787 this.dom.style["-khtml-opacity"] = "";
1793 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1794 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1795 * @return {Roo.Element} this
1797 hide : function(animate){
1798 this.setVisible(false, this.preanim(arguments, 0));
1803 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1804 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1805 * @return {Roo.Element} this
1807 show : function(animate){
1808 this.setVisible(true, this.preanim(arguments, 0));
1813 * @private Test if size has a unit, otherwise appends the default
1815 addUnits : function(size){
1816 return Roo.Element.addUnits(size, this.defaultUnit);
1820 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1821 * @return {Roo.Element} this
1823 beginMeasure : function(){
1825 if(el.offsetWidth || el.offsetHeight){
1826 return this; // offsets work already
1829 var p = this.dom, b = document.body; // start with this element
1830 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1831 var pe = Roo.get(p);
1832 if(pe.getStyle('display') == 'none'){
1833 changed.push({el: p, visibility: pe.getStyle("visibility")});
1834 p.style.visibility = "hidden";
1835 p.style.display = "block";
1839 this._measureChanged = changed;
1845 * Restores displays to before beginMeasure was called
1846 * @return {Roo.Element} this
1848 endMeasure : function(){
1849 var changed = this._measureChanged;
1851 for(var i = 0, len = changed.length; i < len; i++) {
1853 r.el.style.visibility = r.visibility;
1854 r.el.style.display = "none";
1856 this._measureChanged = null;
1862 * Update the innerHTML of this element, optionally searching for and processing scripts
1863 * @param {String} html The new HTML
1864 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1865 * @param {Function} callback For async script loading you can be noticed when the update completes
1866 * @return {Roo.Element} this
1868 update : function(html, loadScripts, callback){
1869 if(typeof html == "undefined"){
1872 if(loadScripts !== true){
1873 this.dom.innerHTML = html;
1874 if(typeof callback == "function"){
1882 html += '<span id="' + id + '"></span>';
1884 E.onAvailable(id, function(){
1885 var hd = document.getElementsByTagName("head")[0];
1886 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1887 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1888 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1891 while(match = re.exec(html)){
1892 var attrs = match[1];
1893 var srcMatch = attrs ? attrs.match(srcRe) : false;
1894 if(srcMatch && srcMatch[2]){
1895 var s = document.createElement("script");
1896 s.src = srcMatch[2];
1897 var typeMatch = attrs.match(typeRe);
1898 if(typeMatch && typeMatch[2]){
1899 s.type = typeMatch[2];
1902 }else if(match[2] && match[2].length > 0){
1903 if(window.execScript) {
1904 window.execScript(match[2]);
1912 window.eval(match[2]);
1916 var el = document.getElementById(id);
1917 if(el){el.parentNode.removeChild(el);}
1918 if(typeof callback == "function"){
1922 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1927 * Direct access to the UpdateManager update() method (takes the same parameters).
1928 * @param {String/Function} url The url for this request or a function to call to get the url
1929 * @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}
1930 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1931 * @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.
1932 * @return {Roo.Element} this
1935 var um = this.getUpdateManager();
1936 um.update.apply(um, arguments);
1941 * Gets this element's UpdateManager
1942 * @return {Roo.UpdateManager} The UpdateManager
1944 getUpdateManager : function(){
1945 if(!this.updateManager){
1946 this.updateManager = new Roo.UpdateManager(this);
1948 return this.updateManager;
1952 * Disables text selection for this element (normalized across browsers)
1953 * @return {Roo.Element} this
1955 unselectable : function(){
1956 this.dom.unselectable = "on";
1957 this.swallowEvent("selectstart", true);
1958 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1959 this.addClass("x-unselectable");
1964 * Calculates the x, y to center this element on the screen
1965 * @return {Array} The x, y values [x, y]
1967 getCenterXY : function(){
1968 return this.getAlignToXY(document, 'c-c');
1972 * Centers the Element in either the viewport, or another Element.
1973 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1975 center : function(centerIn){
1976 this.alignTo(centerIn || document, 'c-c');
1981 * Tests various css rules/browsers to determine if this element uses a border box
1984 isBorderBox : function(){
1985 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1989 * Return a box {x, y, width, height} that can be used to set another elements
1990 * size/location to match this element.
1991 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1992 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1993 * @return {Object} box An object in the format {x, y, width, height}
1995 getBox : function(contentBox, local){
2000 var left = parseInt(this.getStyle("left"), 10) || 0;
2001 var top = parseInt(this.getStyle("top"), 10) || 0;
2004 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
2006 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
2008 var l = this.getBorderWidth("l")+this.getPadding("l");
2009 var r = this.getBorderWidth("r")+this.getPadding("r");
2010 var t = this.getBorderWidth("t")+this.getPadding("t");
2011 var b = this.getBorderWidth("b")+this.getPadding("b");
2012 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)};
2014 bx.right = bx.x + bx.width;
2015 bx.bottom = bx.y + bx.height;
2020 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2021 for more information about the sides.
2022 * @param {String} sides
2025 getFrameWidth : function(sides, onlyContentBox){
2026 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2030 * 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.
2031 * @param {Object} box The box to fill {x, y, width, height}
2032 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2033 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2034 * @return {Roo.Element} this
2036 setBox : function(box, adjust, animate){
2037 var w = box.width, h = box.height;
2038 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2039 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2040 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2042 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2047 * Forces the browser to repaint this element
2048 * @return {Roo.Element} this
2050 repaint : function(){
2052 this.addClass("x-repaint");
2053 setTimeout(function(){
2054 Roo.get(dom).removeClass("x-repaint");
2060 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2061 * then it returns the calculated width of the sides (see getPadding)
2062 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2063 * @return {Object/Number}
2065 getMargins : function(side){
2068 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2069 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2070 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2071 right: parseInt(this.getStyle("margin-right"), 10) || 0
2074 return this.addStyles(side, El.margins);
2079 addStyles : function(sides, styles){
2081 for(var i = 0, len = sides.length; i < len; i++){
2082 v = this.getStyle(styles[sides.charAt(i)]);
2084 w = parseInt(v, 10);
2092 * Creates a proxy element of this element
2093 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2094 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2095 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2096 * @return {Roo.Element} The new proxy element
2098 createProxy : function(config, renderTo, matchBox){
2100 renderTo = Roo.getDom(renderTo);
2102 renderTo = document.body;
2104 config = typeof config == "object" ?
2105 config : {tag : "div", cls: config};
2106 var proxy = Roo.DomHelper.append(renderTo, config, true);
2108 proxy.setBox(this.getBox());
2114 * Puts a mask over this element to disable user interaction. Requires core.css.
2115 * This method can only be applied to elements which accept child nodes.
2116 * @param {String} msg (optional) A message to display in the mask
2117 * @param {String} msgCls (optional) A css class to apply to the msg element
2118 * @return {Element} The mask element
2120 mask : function(msg, msgCls)
2122 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2123 this.setStyle("position", "relative");
2126 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2128 this.addClass("x-masked");
2129 this._mask.setDisplayed(true);
2134 while (dom && dom.style) {
2135 if (!isNaN(parseInt(dom.style.zIndex))) {
2136 z = Math.max(z, parseInt(dom.style.zIndex));
2138 dom = dom.parentNode;
2140 // if we are masking the body - then it hides everything..
2141 if (this.dom == document.body) {
2143 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2144 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2147 if(typeof msg == 'string'){
2149 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2151 var mm = this._maskMsg;
2152 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2153 if (mm.dom.firstChild) { // weird IE issue?
2154 mm.dom.firstChild.innerHTML = msg;
2156 mm.setDisplayed(true);
2158 mm.setStyle('z-index', z + 102);
2160 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2161 this._mask.setHeight(this.getHeight());
2163 this._mask.setStyle('z-index', z + 100);
2169 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2170 * it is cached for reuse.
2172 unmask : function(removeEl){
2174 if(removeEl === true){
2175 this._mask.remove();
2178 this._maskMsg.remove();
2179 delete this._maskMsg;
2182 this._mask.setDisplayed(false);
2184 this._maskMsg.setDisplayed(false);
2188 this.removeClass("x-masked");
2192 * Returns true if this element is masked
2195 isMasked : function(){
2196 return this._mask && this._mask.isVisible();
2200 * Creates an iframe shim for this element to keep selects and other windowed objects from
2202 * @return {Roo.Element} The new shim element
2204 createShim : function(){
2205 var el = document.createElement('iframe');
2206 el.frameBorder = 'no';
2207 el.className = 'roo-shim';
2208 if(Roo.isIE && Roo.isSecure){
2209 el.src = Roo.SSL_SECURE_URL;
2211 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2212 shim.autoBoxAdjust = false;
2217 * Removes this element from the DOM and deletes it from the cache
2219 remove : function(){
2220 if(this.dom.parentNode){
2221 this.dom.parentNode.removeChild(this.dom);
2223 delete El.cache[this.dom.id];
2227 * Sets up event handlers to add and remove a css class when the mouse is over this element
2228 * @param {String} className
2229 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2230 * mouseout events for children elements
2231 * @return {Roo.Element} this
2233 addClassOnOver : function(className, preventFlicker){
2234 this.on("mouseover", function(){
2235 Roo.fly(this, '_internal').addClass(className);
2237 var removeFn = function(e){
2238 if(preventFlicker !== true || !e.within(this, true)){
2239 Roo.fly(this, '_internal').removeClass(className);
2242 this.on("mouseout", removeFn, this.dom);
2247 * Sets up event handlers to add and remove a css class when this element has the focus
2248 * @param {String} className
2249 * @return {Roo.Element} this
2251 addClassOnFocus : function(className){
2252 this.on("focus", function(){
2253 Roo.fly(this, '_internal').addClass(className);
2255 this.on("blur", function(){
2256 Roo.fly(this, '_internal').removeClass(className);
2261 * 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)
2262 * @param {String} className
2263 * @return {Roo.Element} this
2265 addClassOnClick : function(className){
2267 this.on("mousedown", function(){
2268 Roo.fly(dom, '_internal').addClass(className);
2269 var d = Roo.get(document);
2270 var fn = function(){
2271 Roo.fly(dom, '_internal').removeClass(className);
2272 d.removeListener("mouseup", fn);
2274 d.on("mouseup", fn);
2280 * Stops the specified event from bubbling and optionally prevents the default action
2281 * @param {String} eventName
2282 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2283 * @return {Roo.Element} this
2285 swallowEvent : function(eventName, preventDefault){
2286 var fn = function(e){
2287 e.stopPropagation();
2292 if(eventName instanceof Array){
2293 for(var i = 0, len = eventName.length; i < len; i++){
2294 this.on(eventName[i], fn);
2298 this.on(eventName, fn);
2305 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2308 * Sizes this element to its parent element's dimensions performing
2309 * neccessary box adjustments.
2310 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2311 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2312 * @return {Roo.Element} this
2314 fitToParent : function(monitorResize, targetParent) {
2315 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2316 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2317 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2320 var p = Roo.get(targetParent || this.dom.parentNode);
2321 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2322 if (monitorResize === true) {
2323 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2324 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2330 * Gets the next sibling, skipping text nodes
2331 * @return {HTMLElement} The next sibling or null
2333 getNextSibling : function(){
2334 var n = this.dom.nextSibling;
2335 while(n && n.nodeType != 1){
2342 * Gets the previous sibling, skipping text nodes
2343 * @return {HTMLElement} The previous sibling or null
2345 getPrevSibling : function(){
2346 var n = this.dom.previousSibling;
2347 while(n && n.nodeType != 1){
2348 n = n.previousSibling;
2355 * Appends the passed element(s) to this element
2356 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2357 * @return {Roo.Element} this
2359 appendChild: function(el){
2366 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2367 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2368 * automatically generated with the specified attributes.
2369 * @param {HTMLElement} insertBefore (optional) a child element of this element
2370 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2371 * @return {Roo.Element} The new child element
2373 createChild: function(config, insertBefore, returnDom){
2374 config = config || {tag:'div'};
2376 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2378 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2382 * Appends this element to the passed element
2383 * @param {String/HTMLElement/Element} el The new parent element
2384 * @return {Roo.Element} this
2386 appendTo: function(el){
2387 el = Roo.getDom(el);
2388 el.appendChild(this.dom);
2393 * Inserts this element before the passed element in the DOM
2394 * @param {String/HTMLElement/Element} el The element to insert before
2395 * @return {Roo.Element} this
2397 insertBefore: function(el){
2398 el = Roo.getDom(el);
2399 el.parentNode.insertBefore(this.dom, el);
2404 * Inserts this element after the passed element in the DOM
2405 * @param {String/HTMLElement/Element} el The element to insert after
2406 * @return {Roo.Element} this
2408 insertAfter: function(el){
2409 el = Roo.getDom(el);
2410 el.parentNode.insertBefore(this.dom, el.nextSibling);
2415 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2416 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2417 * @return {Roo.Element} The new child
2419 insertFirst: function(el, returnDom){
2421 if(typeof el == 'object' && !el.nodeType){ // dh config
2422 return this.createChild(el, this.dom.firstChild, returnDom);
2424 el = Roo.getDom(el);
2425 this.dom.insertBefore(el, this.dom.firstChild);
2426 return !returnDom ? Roo.get(el) : el;
2431 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2432 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2433 * @param {String} where (optional) 'before' or 'after' defaults to before
2434 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2435 * @return {Roo.Element} the inserted Element
2437 insertSibling: function(el, where, returnDom){
2438 where = where ? where.toLowerCase() : 'before';
2440 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2442 if(typeof el == 'object' && !el.nodeType){ // dh config
2443 if(where == 'after' && !this.dom.nextSibling){
2444 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2446 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2450 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2451 where == 'before' ? this.dom : this.dom.nextSibling);
2460 * Creates and wraps this element with another element
2461 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2462 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2463 * @return {HTMLElement/Element} The newly created wrapper element
2465 wrap: function(config, returnDom){
2467 config = {tag: "div"};
2469 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2470 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2475 * Replaces the passed element with this element
2476 * @param {String/HTMLElement/Element} el The element to replace
2477 * @return {Roo.Element} this
2479 replace: function(el){
2481 this.insertBefore(el);
2487 * Inserts an html fragment into this element
2488 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2489 * @param {String} html The HTML fragment
2490 * @param {Boolean} returnEl True to return an Roo.Element
2491 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2493 insertHtml : function(where, html, returnEl){
2494 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2495 return returnEl ? Roo.get(el) : el;
2499 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2500 * @param {Object} o The object with the attributes
2501 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2502 * @return {Roo.Element} this
2504 set : function(o, useSet){
2506 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2508 if(attr == "style" || typeof o[attr] == "function") { continue; }
2510 el.className = o["cls"];
2513 el.setAttribute(attr, o[attr]);
2520 Roo.DomHelper.applyStyles(el, o.style);
2526 * Convenience method for constructing a KeyMap
2527 * @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:
2528 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2529 * @param {Function} fn The function to call
2530 * @param {Object} scope (optional) The scope of the function
2531 * @return {Roo.KeyMap} The KeyMap created
2533 addKeyListener : function(key, fn, scope){
2535 if(typeof key != "object" || key instanceof Array){
2551 return new Roo.KeyMap(this, config);
2555 * Creates a KeyMap for this element
2556 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2557 * @return {Roo.KeyMap} The KeyMap created
2559 addKeyMap : function(config){
2560 return new Roo.KeyMap(this, config);
2564 * Returns true if this element is scrollable.
2567 isScrollable : function(){
2569 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2573 * 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().
2574 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2575 * @param {Number} value The new scroll value
2576 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2577 * @return {Element} this
2580 scrollTo : function(side, value, animate){
2581 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2583 this.dom[prop] = value;
2585 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2586 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2592 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2593 * within this element's scrollable range.
2594 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2595 * @param {Number} distance How far to scroll the element in pixels
2596 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2597 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2598 * was scrolled as far as it could go.
2600 scroll : function(direction, distance, animate){
2601 if(!this.isScrollable()){
2605 var l = el.scrollLeft, t = el.scrollTop;
2606 var w = el.scrollWidth, h = el.scrollHeight;
2607 var cw = el.clientWidth, ch = el.clientHeight;
2608 direction = direction.toLowerCase();
2609 var scrolled = false;
2610 var a = this.preanim(arguments, 2);
2615 var v = Math.min(l + distance, w-cw);
2616 this.scrollTo("left", v, a);
2623 var v = Math.max(l - distance, 0);
2624 this.scrollTo("left", v, a);
2632 var v = Math.max(t - distance, 0);
2633 this.scrollTo("top", v, a);
2641 var v = Math.min(t + distance, h-ch);
2642 this.scrollTo("top", v, a);
2651 * Translates the passed page coordinates into left/top css values for this element
2652 * @param {Number/Array} x The page x or an array containing [x, y]
2653 * @param {Number} y The page y
2654 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2656 translatePoints : function(x, y){
2657 if(typeof x == 'object' || x instanceof Array){
2660 var p = this.getStyle('position');
2661 var o = this.getXY();
2663 var l = parseInt(this.getStyle('left'), 10);
2664 var t = parseInt(this.getStyle('top'), 10);
2667 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2670 t = (p == "relative") ? 0 : this.dom.offsetTop;
2673 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2677 * Returns the current scroll position of the element.
2678 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2680 getScroll : function(){
2681 var d = this.dom, doc = document;
2682 if(d == doc || d == doc.body){
2683 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2684 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2685 return {left: l, top: t};
2687 return {left: d.scrollLeft, top: d.scrollTop};
2692 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2693 * are convert to standard 6 digit hex color.
2694 * @param {String} attr The css attribute
2695 * @param {String} defaultValue The default value to use when a valid color isn't found
2696 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2699 getColor : function(attr, defaultValue, prefix){
2700 var v = this.getStyle(attr);
2701 if(!v || v == "transparent" || v == "inherit") {
2702 return defaultValue;
2704 var color = typeof prefix == "undefined" ? "#" : prefix;
2705 if(v.substr(0, 4) == "rgb("){
2706 var rvs = v.slice(4, v.length -1).split(",");
2707 for(var i = 0; i < 3; i++){
2708 var h = parseInt(rvs[i]).toString(16);
2715 if(v.substr(0, 1) == "#"){
2717 for(var i = 1; i < 4; i++){
2718 var c = v.charAt(i);
2721 }else if(v.length == 7){
2722 color += v.substr(1);
2726 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2730 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2731 * gradient background, rounded corners and a 4-way shadow.
2732 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2733 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2734 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2735 * @return {Roo.Element} this
2737 boxWrap : function(cls){
2738 cls = cls || 'x-box';
2739 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2740 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2745 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2746 * @param {String} namespace The namespace in which to look for the attribute
2747 * @param {String} name The attribute name
2748 * @return {String} The attribute value
2750 getAttributeNS : Roo.isIE ? function(ns, name){
2752 var type = typeof d[ns+":"+name];
2753 if(type != 'undefined' && type != 'unknown'){
2754 return d[ns+":"+name];
2757 } : function(ns, name){
2759 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2764 * Sets or Returns the value the dom attribute value
2765 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2766 * @param {String} value (optional) The value to set the attribute to
2767 * @return {String} The attribute value
2769 attr : function(name){
2770 if (arguments.length > 1) {
2771 this.dom.setAttribute(name, arguments[1]);
2772 return arguments[1];
2774 if (typeof(name) == 'object') {
2775 for(var i in name) {
2776 this.attr(i, name[i]);
2782 if (!this.dom.hasAttribute(name)) {
2785 return this.dom.getAttribute(name);
2792 var ep = El.prototype;
2795 * Appends an event handler (Shorthand for addListener)
2796 * @param {String} eventName The type of event to append
2797 * @param {Function} fn The method the event invokes
2798 * @param {Object} scope (optional) The scope (this object) of the fn
2799 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2802 ep.on = ep.addListener;
2804 ep.mon = ep.addListener;
2807 * Removes an event handler from this element (shorthand for removeListener)
2808 * @param {String} eventName the type of event to remove
2809 * @param {Function} fn the method the event invokes
2810 * @return {Roo.Element} this
2813 ep.un = ep.removeListener;
2816 * true to automatically adjust width and height settings for box-model issues (default to true)
2818 ep.autoBoxAdjust = true;
2821 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2824 El.addUnits = function(v, defaultUnit){
2825 if(v === "" || v == "auto"){
2828 if(v === undefined){
2831 if(typeof v == "number" || !El.unitPattern.test(v)){
2832 return v + (defaultUnit || 'px');
2837 // special markup used throughout Roo when box wrapping elements
2838 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>';
2840 * Visibility mode constant - Use visibility to hide element
2846 * Visibility mode constant - Use display to hide element
2852 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2853 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2854 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2866 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2867 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2868 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2869 * @return {Element} The Element object
2872 El.get = function(el){
2874 if(!el){ return null; }
2875 if(typeof el == "string"){ // element id
2876 if(!(elm = document.getElementById(el))){
2879 if(ex = El.cache[el]){
2882 ex = El.cache[el] = new El(elm);
2885 }else if(el.tagName){ // dom element
2889 if(ex = El.cache[id]){
2892 ex = El.cache[id] = new El(el);
2895 }else if(el instanceof El){
2897 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2898 // catch case where it hasn't been appended
2899 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2902 }else if(el.isComposite){
2904 }else if(el instanceof Array){
2905 return El.select(el);
2906 }else if(el == document){
2907 // create a bogus element object representing the document object
2909 var f = function(){};
2910 f.prototype = El.prototype;
2912 docEl.dom = document;
2920 El.uncache = function(el){
2921 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2923 delete El.cache[a[i].id || a[i]];
2929 // Garbage collection - uncache elements/purge listeners on orphaned elements
2930 // so we don't hold a reference and cause the browser to retain them
2931 El.garbageCollect = function(){
2932 if(!Roo.enableGarbageCollector){
2933 clearInterval(El.collectorThread);
2936 for(var eid in El.cache){
2937 var el = El.cache[eid], d = el.dom;
2938 // -------------------------------------------------------
2939 // Determining what is garbage:
2940 // -------------------------------------------------------
2942 // dom node is null, definitely garbage
2943 // -------------------------------------------------------
2945 // no parentNode == direct orphan, definitely garbage
2946 // -------------------------------------------------------
2947 // !d.offsetParent && !document.getElementById(eid)
2948 // display none elements have no offsetParent so we will
2949 // also try to look it up by it's id. However, check
2950 // offsetParent first so we don't do unneeded lookups.
2951 // This enables collection of elements that are not orphans
2952 // directly, but somewhere up the line they have an orphan
2954 // -------------------------------------------------------
2955 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2956 delete El.cache[eid];
2957 if(d && Roo.enableListenerCollection){
2963 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2967 El.Flyweight = function(dom){
2970 El.Flyweight.prototype = El.prototype;
2972 El._flyweights = {};
2974 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2975 * the dom node can be overwritten by other code.
2976 * @param {String/HTMLElement} el The dom node or id
2977 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2978 * prevent conflicts (e.g. internally Roo uses "_internal")
2980 * @return {Element} The shared Element object
2982 El.fly = function(el, named){
2983 named = named || '_global';
2984 el = Roo.getDom(el);
2988 if(!El._flyweights[named]){
2989 El._flyweights[named] = new El.Flyweight();
2991 El._flyweights[named].dom = el;
2992 return El._flyweights[named];
2996 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2997 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2998 * Shorthand of {@link Roo.Element#get}
2999 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
3000 * @return {Element} The Element object
3006 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3007 * the dom node can be overwritten by other code.
3008 * Shorthand of {@link Roo.Element#fly}
3009 * @param {String/HTMLElement} el The dom node or id
3010 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3011 * prevent conflicts (e.g. internally Roo uses "_internal")
3013 * @return {Element} The shared Element object
3019 // speedy lookup for elements never to box adjust
3020 var noBoxAdjust = Roo.isStrict ? {
3023 input:1, select:1, textarea:1
3025 if(Roo.isIE || Roo.isGecko){
3026 noBoxAdjust['button'] = 1;
3030 Roo.EventManager.on(window, 'unload', function(){
3032 delete El._flyweights;
3040 Roo.Element.selectorFunction = Roo.DomQuery.select;
3043 Roo.Element.select = function(selector, unique, root){
3045 if(typeof selector == "string"){
3046 els = Roo.Element.selectorFunction(selector, root);
3047 }else if(selector.length !== undefined){
3050 throw "Invalid selector";
3052 if(unique === true){
3053 return new Roo.CompositeElement(els);
3055 return new Roo.CompositeElementLite(els);
3059 * Selects elements based on the passed CSS selector to enable working on them as 1.
3060 * @param {String/Array} selector The CSS selector or an array of elements
3061 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3062 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3063 * @return {CompositeElementLite/CompositeElement}
3067 Roo.select = Roo.Element.select;