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.get(document.body);
199 var excludeStaticParent = this.getStyle('position') === "absolute";
201 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
205 Roo.log(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'));
207 if (excludeStaticParent && parent.getStyle('position') === "static") {
212 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
217 return Roo.get(document.body);
221 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
222 * This is a shortcut for findParentNode() that always returns an Roo.Element.
223 * @param {String} selector The simple selector to test
224 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
225 search as a number or element (defaults to 10 || document.body)
226 * @return {Roo.Element} The matching DOM node (or null if no match was found)
228 up : function(simpleSelector, maxDepth){
229 return this.findParentNode(simpleSelector, maxDepth, true);
235 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
236 * @param {String} selector The simple selector to test
237 * @return {Boolean} True if this element matches the selector, else false
239 is : function(simpleSelector){
240 return Roo.DomQuery.is(this.dom, simpleSelector);
244 * Perform animation on this element.
245 * @param {Object} args The YUI animation control args
246 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
247 * @param {Function} onComplete (optional) Function to call when animation completes
248 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
249 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
250 * @return {Roo.Element} this
252 animate : function(args, duration, onComplete, easing, animType){
253 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
258 * @private Internal animation call
260 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
261 animType = animType || 'run';
263 var anim = Roo.lib.Anim[animType](
265 (opt.duration || defaultDur) || .35,
266 (opt.easing || defaultEase) || 'easeOut',
268 Roo.callback(cb, this);
269 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
277 // private legacy anim prep
278 preanim : function(a, i){
279 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
283 * Removes worthless text nodes
284 * @param {Boolean} forceReclean (optional) By default the element
285 * keeps track if it has been cleaned already so
286 * you can call this over and over. However, if you update the element and
287 * need to force a reclean, you can pass true.
289 clean : function(forceReclean){
290 if(this.isCleaned && forceReclean !== true){
294 var d = this.dom, n = d.firstChild, ni = -1;
296 var nx = n.nextSibling;
297 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
304 this.isCleaned = true;
309 calcOffsetsTo : function(el){
312 var restorePos = false;
313 if(el.getStyle('position') == 'static'){
314 el.position('relative');
319 while(op && op != d && op.tagName != 'HTML'){
322 op = op.offsetParent;
325 el.position('static');
331 * Scrolls this element into view within the passed container.
332 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
333 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
334 * @return {Roo.Element} this
336 scrollIntoView : function(container, hscroll){
337 var c = Roo.getDom(container) || document.body;
340 var o = this.calcOffsetsTo(c),
343 b = t+el.offsetHeight,
344 r = l+el.offsetWidth;
346 var ch = c.clientHeight;
347 var ct = parseInt(c.scrollTop, 10);
348 var cl = parseInt(c.scrollLeft, 10);
350 var cr = cl + c.clientWidth;
358 if(hscroll !== false){
362 c.scrollLeft = r-c.clientWidth;
369 scrollChildIntoView : function(child, hscroll){
370 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
374 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
375 * the new height may not be available immediately.
376 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
377 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
378 * @param {Function} onComplete (optional) Function to call when animation completes
379 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
380 * @return {Roo.Element} this
382 autoHeight : function(animate, duration, onComplete, easing){
383 var oldHeight = this.getHeight();
385 this.setHeight(1); // force clipping
386 setTimeout(function(){
387 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
389 this.setHeight(height);
391 if(typeof onComplete == "function"){
395 this.setHeight(oldHeight); // restore original height
396 this.setHeight(height, animate, duration, function(){
398 if(typeof onComplete == "function") { onComplete(); }
399 }.createDelegate(this), easing);
401 }.createDelegate(this), 0);
406 * Returns true if this element is an ancestor of the passed element
407 * @param {HTMLElement/String} el The element to check
408 * @return {Boolean} True if this element is an ancestor of el, else false
410 contains : function(el){
411 if(!el){return false;}
412 return D.isAncestor(this.dom, el.dom ? el.dom : el);
416 * Checks whether the element is currently visible using both visibility and display properties.
417 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
418 * @return {Boolean} True if the element is currently visible, else false
420 isVisible : function(deep) {
421 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
422 if(deep !== true || !vis){
425 var p = this.dom.parentNode;
426 while(p && p.tagName.toLowerCase() != "body"){
427 if(!Roo.fly(p, '_isVisible').isVisible()){
436 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
437 * @param {String} selector The CSS selector
438 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
439 * @return {CompositeElement/CompositeElementLite} The composite element
441 select : function(selector, unique){
442 return El.select(selector, unique, this.dom);
446 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
447 * @param {String} selector The CSS selector
448 * @return {Array} An array of the matched nodes
450 query : function(selector, unique){
451 return Roo.DomQuery.select(selector, this.dom);
455 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
456 * @param {String} selector The CSS selector
457 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
458 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
460 child : function(selector, returnDom){
461 var n = Roo.DomQuery.selectNode(selector, this.dom);
462 return returnDom ? n : Roo.get(n);
466 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
467 * @param {String} selector The CSS selector
468 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
469 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
471 down : function(selector, returnDom){
472 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
473 return returnDom ? n : Roo.get(n);
477 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
478 * @param {String} group The group the DD object is member of
479 * @param {Object} config The DD config object
480 * @param {Object} overrides An object containing methods to override/implement on the DD object
481 * @return {Roo.dd.DD} The DD object
483 initDD : function(group, config, overrides){
484 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
485 return Roo.apply(dd, overrides);
489 * Initializes a {@link Roo.dd.DDProxy} object for this element.
490 * @param {String} group The group the DDProxy object is member of
491 * @param {Object} config The DDProxy config object
492 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
493 * @return {Roo.dd.DDProxy} The DDProxy object
495 initDDProxy : function(group, config, overrides){
496 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
497 return Roo.apply(dd, overrides);
501 * Initializes a {@link Roo.dd.DDTarget} object for this element.
502 * @param {String} group The group the DDTarget object is member of
503 * @param {Object} config The DDTarget config object
504 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
505 * @return {Roo.dd.DDTarget} The DDTarget object
507 initDDTarget : function(group, config, overrides){
508 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
509 return Roo.apply(dd, overrides);
513 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
514 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
515 * @param {Boolean} visible Whether the element is visible
516 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
517 * @return {Roo.Element} this
519 setVisible : function(visible, animate){
521 if(this.visibilityMode == El.DISPLAY){
522 this.setDisplayed(visible);
525 this.dom.style.visibility = visible ? "visible" : "hidden";
528 // closure for composites
530 var visMode = this.visibilityMode;
532 this.setOpacity(.01);
533 this.setVisible(true);
535 this.anim({opacity: { to: (visible?1:0) }},
536 this.preanim(arguments, 1),
537 null, .35, 'easeIn', function(){
539 if(visMode == El.DISPLAY){
540 dom.style.display = "none";
542 dom.style.visibility = "hidden";
544 Roo.get(dom).setOpacity(1);
552 * Returns true if display is not "none"
555 isDisplayed : function() {
556 return this.getStyle("display") != "none";
560 * Toggles the element's visibility or display, depending on visibility mode.
561 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
562 * @return {Roo.Element} this
564 toggle : function(animate){
565 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
570 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
571 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
572 * @return {Roo.Element} this
574 setDisplayed : function(value) {
575 if(typeof value == "boolean"){
576 value = value ? this.originalDisplay : "none";
578 this.setStyle("display", value);
583 * Tries to focus the element. Any exceptions are caught and ignored.
584 * @return {Roo.Element} this
594 * Tries to blur the element. Any exceptions are caught and ignored.
595 * @return {Roo.Element} this
605 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
606 * @param {String/Array} className The CSS class to add, or an array of classes
607 * @return {Roo.Element} this
609 addClass : function(className){
610 if(className instanceof Array){
611 for(var i = 0, len = className.length; i < len; i++) {
612 this.addClass(className[i]);
615 if(className && !this.hasClass(className)){
616 this.dom.className = this.dom.className + " " + className;
623 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
624 * @param {String/Array} className The CSS class to add, or an array of classes
625 * @return {Roo.Element} this
627 radioClass : function(className){
628 var siblings = this.dom.parentNode.childNodes;
629 for(var i = 0; i < siblings.length; i++) {
632 Roo.get(s).removeClass(className);
635 this.addClass(className);
640 * Removes one or more CSS classes from the element.
641 * @param {String/Array} className The CSS class to remove, or an array of classes
642 * @return {Roo.Element} this
644 removeClass : function(className){
645 if(!className || !this.dom.className){
648 if(className instanceof Array){
649 for(var i = 0, len = className.length; i < len; i++) {
650 this.removeClass(className[i]);
653 if(this.hasClass(className)){
654 var re = this.classReCache[className];
656 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
657 this.classReCache[className] = re;
660 this.dom.className.replace(re, " ");
670 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
671 * @param {String} className The CSS class to toggle
672 * @return {Roo.Element} this
674 toggleClass : function(className){
675 if(this.hasClass(className)){
676 this.removeClass(className);
678 this.addClass(className);
684 * Checks if the specified CSS class exists on this element's DOM node.
685 * @param {String} className The CSS class to check for
686 * @return {Boolean} True if the class exists, else false
688 hasClass : function(className){
689 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
693 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
694 * @param {String} oldClassName The CSS class to replace
695 * @param {String} newClassName The replacement CSS class
696 * @return {Roo.Element} this
698 replaceClass : function(oldClassName, newClassName){
699 this.removeClass(oldClassName);
700 this.addClass(newClassName);
705 * Returns an object with properties matching the styles requested.
706 * For example, el.getStyles('color', 'font-size', 'width') might return
707 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
708 * @param {String} style1 A style name
709 * @param {String} style2 A style name
710 * @param {String} etc.
711 * @return {Object} The style object
713 getStyles : function(){
714 var a = arguments, len = a.length, r = {};
715 for(var i = 0; i < len; i++){
716 r[a[i]] = this.getStyle(a[i]);
722 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
723 * @param {String} property The style property whose value is returned.
724 * @return {String} The current value of the style property for this element.
726 getStyle : function(){
727 return view && view.getComputedStyle ?
729 var el = this.dom, v, cs, camel;
733 if(el.style && (v = el.style[prop])){
736 if(cs = view.getComputedStyle(el, "")){
737 if(!(camel = propCache[prop])){
738 camel = propCache[prop] = prop.replace(camelRe, camelFn);
745 var el = this.dom, v, cs, camel;
746 if(prop == 'opacity'){
747 if(typeof el.style.filter == 'string'){
748 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
750 var fv = parseFloat(m[1]);
752 return fv ? fv / 100 : 0;
757 }else if(prop == 'float'){
760 if(!(camel = propCache[prop])){
761 camel = propCache[prop] = prop.replace(camelRe, camelFn);
763 if(v = el.style[camel]){
766 if(cs = el.currentStyle){
774 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
775 * @param {String/Object} property The style property to be set, or an object of multiple styles.
776 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
777 * @return {Roo.Element} this
779 setStyle : function(prop, value){
780 if(typeof prop == "string"){
782 if (prop == 'float') {
783 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
788 if(!(camel = propCache[prop])){
789 camel = propCache[prop] = prop.replace(camelRe, camelFn);
792 if(camel == 'opacity') {
793 this.setOpacity(value);
795 this.dom.style[camel] = value;
798 for(var style in prop){
799 if(typeof prop[style] != "function"){
800 this.setStyle(style, prop[style]);
808 * More flexible version of {@link #setStyle} for setting style properties.
809 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
810 * a function which returns such a specification.
811 * @return {Roo.Element} this
813 applyStyles : function(style){
814 Roo.DomHelper.applyStyles(this.dom, style);
819 * 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).
820 * @return {Number} The X position of the element
823 return D.getX(this.dom);
827 * 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).
828 * @return {Number} The Y position of the element
831 return D.getY(this.dom);
835 * 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).
836 * @return {Array} The XY position of the element
839 return D.getXY(this.dom);
843 * 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).
844 * @param {Number} The X position of the element
845 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
846 * @return {Roo.Element} this
848 setX : function(x, animate){
852 this.setXY([x, this.getY()], this.preanim(arguments, 1));
858 * 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).
859 * @param {Number} The Y position of the element
860 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
861 * @return {Roo.Element} this
863 setY : function(y, animate){
867 this.setXY([this.getX(), y], this.preanim(arguments, 1));
873 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
874 * @param {String} left The left CSS property value
875 * @return {Roo.Element} this
877 setLeft : function(left){
878 this.setStyle("left", this.addUnits(left));
883 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
884 * @param {String} top The top CSS property value
885 * @return {Roo.Element} this
887 setTop : function(top){
888 this.setStyle("top", this.addUnits(top));
893 * Sets the element's CSS right style.
894 * @param {String} right The right CSS property value
895 * @return {Roo.Element} this
897 setRight : function(right){
898 this.setStyle("right", this.addUnits(right));
903 * Sets the element's CSS bottom style.
904 * @param {String} bottom The bottom CSS property value
905 * @return {Roo.Element} this
907 setBottom : function(bottom){
908 this.setStyle("bottom", this.addUnits(bottom));
913 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
914 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
915 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
916 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
917 * @return {Roo.Element} this
919 setXY : function(pos, animate){
921 D.setXY(this.dom, pos);
923 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
929 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
930 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
931 * @param {Number} x X value for new position (coordinates are page-based)
932 * @param {Number} y Y value for new position (coordinates are page-based)
933 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
934 * @return {Roo.Element} this
936 setLocation : function(x, y, animate){
937 this.setXY([x, y], this.preanim(arguments, 2));
942 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
943 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
944 * @param {Number} x X value for new position (coordinates are page-based)
945 * @param {Number} y Y value for new position (coordinates are page-based)
946 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
947 * @return {Roo.Element} this
949 moveTo : function(x, y, animate){
950 this.setXY([x, y], this.preanim(arguments, 2));
955 * Returns the region of the given element.
956 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
957 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
959 getRegion : function(){
960 return D.getRegion(this.dom);
964 * Returns the offset height of the element
965 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
966 * @return {Number} The element's height
968 getHeight : function(contentHeight){
969 var h = this.dom.offsetHeight || 0;
970 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
974 * Returns the offset width of the element
975 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
976 * @return {Number} The element's width
978 getWidth : function(contentWidth){
979 var w = this.dom.offsetWidth || 0;
980 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
984 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
985 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
986 * if a height has not been set using CSS.
989 getComputedHeight : function(){
990 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
992 h = parseInt(this.getStyle('height'), 10) || 0;
993 if(!this.isBorderBox()){
994 h += this.getFrameWidth('tb');
1001 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1002 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1003 * if a width has not been set using CSS.
1006 getComputedWidth : function(){
1007 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1009 w = parseInt(this.getStyle('width'), 10) || 0;
1010 if(!this.isBorderBox()){
1011 w += this.getFrameWidth('lr');
1018 * Returns the size of the element.
1019 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1020 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1022 getSize : function(contentSize){
1023 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1027 * Returns the width and height of the viewport.
1028 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1030 getViewSize : function(){
1031 var d = this.dom, doc = document, aw = 0, ah = 0;
1032 if(d == doc || d == doc.body){
1033 return {width : D.getViewWidth(), height: D.getViewHeight()};
1036 width : d.clientWidth,
1037 height: d.clientHeight
1043 * Returns the value of the "value" attribute
1044 * @param {Boolean} asNumber true to parse the value as a number
1045 * @return {String/Number}
1047 getValue : function(asNumber){
1048 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1052 adjustWidth : function(width){
1053 if(typeof width == "number"){
1054 if(this.autoBoxAdjust && !this.isBorderBox()){
1055 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1065 adjustHeight : function(height){
1066 if(typeof height == "number"){
1067 if(this.autoBoxAdjust && !this.isBorderBox()){
1068 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1078 * Set the width of the element
1079 * @param {Number} width The new width
1080 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1081 * @return {Roo.Element} this
1083 setWidth : function(width, animate){
1084 width = this.adjustWidth(width);
1086 this.dom.style.width = this.addUnits(width);
1088 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1094 * Set the height of the element
1095 * @param {Number} height The new height
1096 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1097 * @return {Roo.Element} this
1099 setHeight : function(height, animate){
1100 height = this.adjustHeight(height);
1102 this.dom.style.height = this.addUnits(height);
1104 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1110 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1111 * @param {Number} width The new width
1112 * @param {Number} height The new height
1113 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1114 * @return {Roo.Element} this
1116 setSize : function(width, height, animate){
1117 if(typeof width == "object"){ // in case of object from getSize()
1118 height = width.height; width = width.width;
1120 width = this.adjustWidth(width); height = this.adjustHeight(height);
1122 this.dom.style.width = this.addUnits(width);
1123 this.dom.style.height = this.addUnits(height);
1125 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1131 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1132 * @param {Number} x X value for new position (coordinates are page-based)
1133 * @param {Number} y Y value for new position (coordinates are page-based)
1134 * @param {Number} width The new width
1135 * @param {Number} height The new height
1136 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1137 * @return {Roo.Element} this
1139 setBounds : function(x, y, width, height, animate){
1141 this.setSize(width, height);
1142 this.setLocation(x, y);
1144 width = this.adjustWidth(width); height = this.adjustHeight(height);
1145 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1146 this.preanim(arguments, 4), 'motion');
1152 * 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.
1153 * @param {Roo.lib.Region} region The region to fill
1154 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1155 * @return {Roo.Element} this
1157 setRegion : function(region, animate){
1158 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1163 * Appends an event handler
1165 * @param {String} eventName The type of event to append
1166 * @param {Function} fn The method the event invokes
1167 * @param {Object} scope (optional) The scope (this object) of the fn
1168 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1170 addListener : function(eventName, fn, scope, options){
1172 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1177 * Removes an event handler from this element
1178 * @param {String} eventName the type of event to remove
1179 * @param {Function} fn the method the event invokes
1180 * @return {Roo.Element} this
1182 removeListener : function(eventName, fn){
1183 Roo.EventManager.removeListener(this.dom, eventName, fn);
1188 * Removes all previous added listeners from this element
1189 * @return {Roo.Element} this
1191 removeAllListeners : function(){
1192 E.purgeElement(this.dom);
1196 relayEvent : function(eventName, observable){
1197 this.on(eventName, function(e){
1198 observable.fireEvent(eventName, e);
1203 * Set the opacity of the element
1204 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1205 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1206 * @return {Roo.Element} this
1208 setOpacity : function(opacity, animate){
1210 var s = this.dom.style;
1213 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1214 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1216 s.opacity = opacity;
1219 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1225 * Gets the left X coordinate
1226 * @param {Boolean} local True to get the local css position instead of page coordinate
1229 getLeft : function(local){
1233 return parseInt(this.getStyle("left"), 10) || 0;
1238 * Gets the right X coordinate of the element (element X position + element width)
1239 * @param {Boolean} local True to get the local css position instead of page coordinate
1242 getRight : function(local){
1244 return this.getX() + this.getWidth();
1246 return (this.getLeft(true) + this.getWidth()) || 0;
1251 * Gets the top Y coordinate
1252 * @param {Boolean} local True to get the local css position instead of page coordinate
1255 getTop : function(local) {
1259 return parseInt(this.getStyle("top"), 10) || 0;
1264 * Gets the bottom Y coordinate of the element (element Y position + element height)
1265 * @param {Boolean} local True to get the local css position instead of page coordinate
1268 getBottom : function(local){
1270 return this.getY() + this.getHeight();
1272 return (this.getTop(true) + this.getHeight()) || 0;
1277 * Initializes positioning on this element. If a desired position is not passed, it will make the
1278 * the element positioned relative IF it is not already positioned.
1279 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1280 * @param {Number} zIndex (optional) The zIndex to apply
1281 * @param {Number} x (optional) Set the page X position
1282 * @param {Number} y (optional) Set the page Y position
1284 position : function(pos, zIndex, x, y){
1286 if(this.getStyle('position') == 'static'){
1287 this.setStyle('position', 'relative');
1290 this.setStyle("position", pos);
1293 this.setStyle("z-index", zIndex);
1295 if(x !== undefined && y !== undefined){
1297 }else if(x !== undefined){
1299 }else if(y !== undefined){
1305 * Clear positioning back to the default when the document was loaded
1306 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1307 * @return {Roo.Element} this
1309 clearPositioning : function(value){
1317 "position" : "static"
1323 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1324 * snapshot before performing an update and then restoring the element.
1327 getPositioning : function(){
1328 var l = this.getStyle("left");
1329 var t = this.getStyle("top");
1331 "position" : this.getStyle("position"),
1333 "right" : l ? "" : this.getStyle("right"),
1335 "bottom" : t ? "" : this.getStyle("bottom"),
1336 "z-index" : this.getStyle("z-index")
1341 * Gets the width of the border(s) for the specified side(s)
1342 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1343 * passing lr would get the border (l)eft width + the border (r)ight width.
1344 * @return {Number} The width of the sides passed added together
1346 getBorderWidth : function(side){
1347 return this.addStyles(side, El.borders);
1351 * Gets the width of the padding(s) for the specified side(s)
1352 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1353 * passing lr would get the padding (l)eft + the padding (r)ight.
1354 * @return {Number} The padding of the sides passed added together
1356 getPadding : function(side){
1357 return this.addStyles(side, El.paddings);
1361 * Set positioning with an object returned by getPositioning().
1362 * @param {Object} posCfg
1363 * @return {Roo.Element} this
1365 setPositioning : function(pc){
1366 this.applyStyles(pc);
1367 if(pc.right == "auto"){
1368 this.dom.style.right = "";
1370 if(pc.bottom == "auto"){
1371 this.dom.style.bottom = "";
1377 fixDisplay : function(){
1378 if(this.getStyle("display") == "none"){
1379 this.setStyle("visibility", "hidden");
1380 this.setStyle("display", this.originalDisplay); // first try reverting to default
1381 if(this.getStyle("display") == "none"){ // if that fails, default to block
1382 this.setStyle("display", "block");
1388 * Quick set left and top adding default units
1389 * @param {String} left The left CSS property value
1390 * @param {String} top The top CSS property value
1391 * @return {Roo.Element} this
1393 setLeftTop : function(left, top){
1394 this.dom.style.left = this.addUnits(left);
1395 this.dom.style.top = this.addUnits(top);
1400 * Move this element relative to its current position.
1401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1402 * @param {Number} distance How far to move the element in pixels
1403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1404 * @return {Roo.Element} this
1406 move : function(direction, distance, animate){
1407 var xy = this.getXY();
1408 direction = direction.toLowerCase();
1412 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1416 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1421 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1426 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1433 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1434 * @return {Roo.Element} this
1437 if(!this.isClipped){
1438 this.isClipped = true;
1439 this.originalClip = {
1440 "o": this.getStyle("overflow"),
1441 "x": this.getStyle("overflow-x"),
1442 "y": this.getStyle("overflow-y")
1444 this.setStyle("overflow", "hidden");
1445 this.setStyle("overflow-x", "hidden");
1446 this.setStyle("overflow-y", "hidden");
1452 * Return clipping (overflow) to original clipping before clip() was called
1453 * @return {Roo.Element} this
1455 unclip : function(){
1457 this.isClipped = false;
1458 var o = this.originalClip;
1459 if(o.o){this.setStyle("overflow", o.o);}
1460 if(o.x){this.setStyle("overflow-x", o.x);}
1461 if(o.y){this.setStyle("overflow-y", o.y);}
1468 * Gets the x,y coordinates specified by the anchor position on the element.
1469 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1470 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1471 * {width: (target width), height: (target height)} (defaults to the element's current size)
1472 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1473 * @return {Array} [x, y] An array containing the element's x and y coordinates
1475 getAnchorXY : function(anchor, local, s){
1476 //Passing a different size is useful for pre-calculating anchors,
1477 //especially for anchored animations that change the el size.
1479 var w, h, vp = false;
1482 if(d == document.body || d == document){
1484 w = D.getViewWidth(); h = D.getViewHeight();
1486 w = this.getWidth(); h = this.getHeight();
1489 w = s.width; h = s.height;
1491 var x = 0, y = 0, r = Math.round;
1492 switch((anchor || "tl").toLowerCase()){
1534 var sc = this.getScroll();
1535 return [x + sc.left, y + sc.top];
1537 //Add the element's offset xy
1538 var o = this.getXY();
1539 return [x+o[0], y+o[1]];
1543 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1544 * supported position values.
1545 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1546 * @param {String} position The position to align to.
1547 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1548 * @return {Array} [x, y]
1550 getAlignToXY : function(el, p, o){
1554 throw "Element.alignTo with an element that doesn't exist";
1556 var c = false; //constrain to viewport
1557 var p1 = "", p2 = "";
1564 }else if(p.indexOf("-") == -1){
1567 p = p.toLowerCase();
1568 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1570 throw "Element.alignTo with an invalid alignment " + p;
1572 p1 = m[1]; p2 = m[2]; c = !!m[3];
1574 //Subtract the aligned el's internal xy from the target's offset xy
1575 //plus custom offset to get the aligned el's new offset xy
1576 var a1 = this.getAnchorXY(p1, true);
1577 var a2 = el.getAnchorXY(p2, false);
1578 var x = a2[0] - a1[0] + o[0];
1579 var y = a2[1] - a1[1] + o[1];
1581 //constrain the aligned el to viewport if necessary
1582 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1583 // 5px of margin for ie
1584 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1586 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1587 //perpendicular to the vp border, allow the aligned el to slide on that border,
1588 //otherwise swap the aligned el to the opposite border of the target.
1589 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1590 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1591 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1592 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1595 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1596 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1598 if((x+w) > dw + scrollX){
1599 x = swapX ? r.left-w : dw+scrollX-w;
1602 x = swapX ? r.right : scrollX;
1604 if((y+h) > dh + scrollY){
1605 y = swapY ? r.top-h : dh+scrollY-h;
1608 y = swapY ? r.bottom : scrollY;
1615 getConstrainToXY : function(){
1616 var os = {top:0, left:0, bottom:0, right: 0};
1618 return function(el, local, offsets, proposedXY){
1620 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1622 var vw, vh, vx = 0, vy = 0;
1623 if(el.dom == document.body || el.dom == document){
1624 vw = Roo.lib.Dom.getViewWidth();
1625 vh = Roo.lib.Dom.getViewHeight();
1627 vw = el.dom.clientWidth;
1628 vh = el.dom.clientHeight;
1630 var vxy = el.getXY();
1636 var s = el.getScroll();
1638 vx += offsets.left + s.left;
1639 vy += offsets.top + s.top;
1641 vw -= offsets.right;
1642 vh -= offsets.bottom;
1647 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1648 var x = xy[0], y = xy[1];
1649 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1651 // only move it if it needs it
1654 // first validate right/bottom
1663 // then make sure top/left isn't negative
1672 return moved ? [x, y] : false;
1677 adjustForConstraints : function(xy, parent, offsets){
1678 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1682 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1683 * document it aligns it to the viewport.
1684 * The position parameter is optional, and can be specified in any one of the following formats:
1686 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1687 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1688 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1689 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1690 * <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
1691 * element's anchor point, and the second value is used as the target's anchor point.</li>
1693 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1694 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1695 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1696 * that specified in order to enforce the viewport constraints.
1697 * Following are all of the supported anchor positions:
1700 ----- -----------------------------
1701 tl The top left corner (default)
1702 t The center of the top edge
1703 tr The top right corner
1704 l The center of the left edge
1705 c In the center of the element
1706 r The center of the right edge
1707 bl The bottom left corner
1708 b The center of the bottom edge
1709 br The bottom right corner
1713 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1714 el.alignTo("other-el");
1716 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1717 el.alignTo("other-el", "tr?");
1719 // align the bottom right corner of el with the center left edge of other-el
1720 el.alignTo("other-el", "br-l?");
1722 // align the center of el with the bottom left corner of other-el and
1723 // adjust the x position by -6 pixels (and the y position by 0)
1724 el.alignTo("other-el", "c-bl", [-6, 0]);
1726 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1727 * @param {String} position The position to align to.
1728 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1729 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1730 * @return {Roo.Element} this
1732 alignTo : function(element, position, offsets, animate){
1733 var xy = this.getAlignToXY(element, position, offsets);
1734 this.setXY(xy, this.preanim(arguments, 3));
1739 * Anchors an element to another element and realigns it when the window is resized.
1740 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1741 * @param {String} position The position to align to.
1742 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1743 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1744 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1745 * is a number, it is used as the buffer delay (defaults to 50ms).
1746 * @param {Function} callback The function to call after the animation finishes
1747 * @return {Roo.Element} this
1749 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1750 var action = function(){
1751 this.alignTo(el, alignment, offsets, animate);
1752 Roo.callback(callback, this);
1754 Roo.EventManager.onWindowResize(action, this);
1755 var tm = typeof monitorScroll;
1756 if(tm != 'undefined'){
1757 Roo.EventManager.on(window, 'scroll', action, this,
1758 {buffer: tm == 'number' ? monitorScroll : 50});
1760 action.call(this); // align immediately
1764 * Clears any opacity settings from this element. Required in some cases for IE.
1765 * @return {Roo.Element} this
1767 clearOpacity : function(){
1768 if (window.ActiveXObject) {
1769 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1770 this.dom.style.filter = "";
1773 this.dom.style.opacity = "";
1774 this.dom.style["-moz-opacity"] = "";
1775 this.dom.style["-khtml-opacity"] = "";
1781 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1782 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1783 * @return {Roo.Element} this
1785 hide : function(animate){
1786 this.setVisible(false, this.preanim(arguments, 0));
1791 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1792 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1793 * @return {Roo.Element} this
1795 show : function(animate){
1796 this.setVisible(true, this.preanim(arguments, 0));
1801 * @private Test if size has a unit, otherwise appends the default
1803 addUnits : function(size){
1804 return Roo.Element.addUnits(size, this.defaultUnit);
1808 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1809 * @return {Roo.Element} this
1811 beginMeasure : function(){
1813 if(el.offsetWidth || el.offsetHeight){
1814 return this; // offsets work already
1817 var p = this.dom, b = document.body; // start with this element
1818 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1819 var pe = Roo.get(p);
1820 if(pe.getStyle('display') == 'none'){
1821 changed.push({el: p, visibility: pe.getStyle("visibility")});
1822 p.style.visibility = "hidden";
1823 p.style.display = "block";
1827 this._measureChanged = changed;
1833 * Restores displays to before beginMeasure was called
1834 * @return {Roo.Element} this
1836 endMeasure : function(){
1837 var changed = this._measureChanged;
1839 for(var i = 0, len = changed.length; i < len; i++) {
1841 r.el.style.visibility = r.visibility;
1842 r.el.style.display = "none";
1844 this._measureChanged = null;
1850 * Update the innerHTML of this element, optionally searching for and processing scripts
1851 * @param {String} html The new HTML
1852 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1853 * @param {Function} callback For async script loading you can be noticed when the update completes
1854 * @return {Roo.Element} this
1856 update : function(html, loadScripts, callback){
1857 if(typeof html == "undefined"){
1860 if(loadScripts !== true){
1861 this.dom.innerHTML = html;
1862 if(typeof callback == "function"){
1870 html += '<span id="' + id + '"></span>';
1872 E.onAvailable(id, function(){
1873 var hd = document.getElementsByTagName("head")[0];
1874 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1875 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1876 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1879 while(match = re.exec(html)){
1880 var attrs = match[1];
1881 var srcMatch = attrs ? attrs.match(srcRe) : false;
1882 if(srcMatch && srcMatch[2]){
1883 var s = document.createElement("script");
1884 s.src = srcMatch[2];
1885 var typeMatch = attrs.match(typeRe);
1886 if(typeMatch && typeMatch[2]){
1887 s.type = typeMatch[2];
1890 }else if(match[2] && match[2].length > 0){
1891 if(window.execScript) {
1892 window.execScript(match[2]);
1900 window.eval(match[2]);
1904 var el = document.getElementById(id);
1905 if(el){el.parentNode.removeChild(el);}
1906 if(typeof callback == "function"){
1910 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1915 * Direct access to the UpdateManager update() method (takes the same parameters).
1916 * @param {String/Function} url The url for this request or a function to call to get the url
1917 * @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}
1918 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1919 * @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.
1920 * @return {Roo.Element} this
1923 var um = this.getUpdateManager();
1924 um.update.apply(um, arguments);
1929 * Gets this element's UpdateManager
1930 * @return {Roo.UpdateManager} The UpdateManager
1932 getUpdateManager : function(){
1933 if(!this.updateManager){
1934 this.updateManager = new Roo.UpdateManager(this);
1936 return this.updateManager;
1940 * Disables text selection for this element (normalized across browsers)
1941 * @return {Roo.Element} this
1943 unselectable : function(){
1944 this.dom.unselectable = "on";
1945 this.swallowEvent("selectstart", true);
1946 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1947 this.addClass("x-unselectable");
1952 * Calculates the x, y to center this element on the screen
1953 * @return {Array} The x, y values [x, y]
1955 getCenterXY : function(){
1956 return this.getAlignToXY(document, 'c-c');
1960 * Centers the Element in either the viewport, or another Element.
1961 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1963 center : function(centerIn){
1964 this.alignTo(centerIn || document, 'c-c');
1969 * Tests various css rules/browsers to determine if this element uses a border box
1972 isBorderBox : function(){
1973 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1977 * Return a box {x, y, width, height} that can be used to set another elements
1978 * size/location to match this element.
1979 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1980 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1981 * @return {Object} box An object in the format {x, y, width, height}
1983 getBox : function(contentBox, local){
1988 var left = parseInt(this.getStyle("left"), 10) || 0;
1989 var top = parseInt(this.getStyle("top"), 10) || 0;
1992 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
1994 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
1996 var l = this.getBorderWidth("l")+this.getPadding("l");
1997 var r = this.getBorderWidth("r")+this.getPadding("r");
1998 var t = this.getBorderWidth("t")+this.getPadding("t");
1999 var b = this.getBorderWidth("b")+this.getPadding("b");
2000 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)};
2002 bx.right = bx.x + bx.width;
2003 bx.bottom = bx.y + bx.height;
2008 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2009 for more information about the sides.
2010 * @param {String} sides
2013 getFrameWidth : function(sides, onlyContentBox){
2014 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2018 * 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.
2019 * @param {Object} box The box to fill {x, y, width, height}
2020 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2021 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2022 * @return {Roo.Element} this
2024 setBox : function(box, adjust, animate){
2025 var w = box.width, h = box.height;
2026 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2027 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2028 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2030 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2035 * Forces the browser to repaint this element
2036 * @return {Roo.Element} this
2038 repaint : function(){
2040 this.addClass("x-repaint");
2041 setTimeout(function(){
2042 Roo.get(dom).removeClass("x-repaint");
2048 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2049 * then it returns the calculated width of the sides (see getPadding)
2050 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2051 * @return {Object/Number}
2053 getMargins : function(side){
2056 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2057 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2058 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2059 right: parseInt(this.getStyle("margin-right"), 10) || 0
2062 return this.addStyles(side, El.margins);
2067 addStyles : function(sides, styles){
2069 for(var i = 0, len = sides.length; i < len; i++){
2070 v = this.getStyle(styles[sides.charAt(i)]);
2072 w = parseInt(v, 10);
2080 * Creates a proxy element of this element
2081 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2082 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2083 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2084 * @return {Roo.Element} The new proxy element
2086 createProxy : function(config, renderTo, matchBox){
2088 renderTo = Roo.getDom(renderTo);
2090 renderTo = document.body;
2092 config = typeof config == "object" ?
2093 config : {tag : "div", cls: config};
2094 var proxy = Roo.DomHelper.append(renderTo, config, true);
2096 proxy.setBox(this.getBox());
2102 * Puts a mask over this element to disable user interaction. Requires core.css.
2103 * This method can only be applied to elements which accept child nodes.
2104 * @param {String} msg (optional) A message to display in the mask
2105 * @param {String} msgCls (optional) A css class to apply to the msg element
2106 * @return {Element} The mask element
2108 mask : function(msg, msgCls)
2110 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2111 this.setStyle("position", "relative");
2114 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2116 this.addClass("x-masked");
2117 this._mask.setDisplayed(true);
2122 while (dom && dom.style) {
2123 if (!isNaN(parseInt(dom.style.zIndex))) {
2124 z = Math.max(z, parseInt(dom.style.zIndex));
2126 dom = dom.parentNode;
2128 // if we are masking the body - then it hides everything..
2129 if (this.dom == document.body) {
2131 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2132 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2135 if(typeof msg == 'string'){
2137 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2139 var mm = this._maskMsg;
2140 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2141 if (mm.dom.firstChild) { // weird IE issue?
2142 mm.dom.firstChild.innerHTML = msg;
2144 mm.setDisplayed(true);
2146 mm.setStyle('z-index', z + 102);
2148 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2149 this._mask.setHeight(this.getHeight());
2151 this._mask.setStyle('z-index', z + 100);
2157 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2158 * it is cached for reuse.
2160 unmask : function(removeEl){
2162 if(removeEl === true){
2163 this._mask.remove();
2166 this._maskMsg.remove();
2167 delete this._maskMsg;
2170 this._mask.setDisplayed(false);
2172 this._maskMsg.setDisplayed(false);
2176 this.removeClass("x-masked");
2180 * Returns true if this element is masked
2183 isMasked : function(){
2184 return this._mask && this._mask.isVisible();
2188 * Creates an iframe shim for this element to keep selects and other windowed objects from
2190 * @return {Roo.Element} The new shim element
2192 createShim : function(){
2193 var el = document.createElement('iframe');
2194 el.frameBorder = 'no';
2195 el.className = 'roo-shim';
2196 if(Roo.isIE && Roo.isSecure){
2197 el.src = Roo.SSL_SECURE_URL;
2199 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2200 shim.autoBoxAdjust = false;
2205 * Removes this element from the DOM and deletes it from the cache
2207 remove : function(){
2208 if(this.dom.parentNode){
2209 this.dom.parentNode.removeChild(this.dom);
2211 delete El.cache[this.dom.id];
2215 * Sets up event handlers to add and remove a css class when the mouse is over this element
2216 * @param {String} className
2217 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2218 * mouseout events for children elements
2219 * @return {Roo.Element} this
2221 addClassOnOver : function(className, preventFlicker){
2222 this.on("mouseover", function(){
2223 Roo.fly(this, '_internal').addClass(className);
2225 var removeFn = function(e){
2226 if(preventFlicker !== true || !e.within(this, true)){
2227 Roo.fly(this, '_internal').removeClass(className);
2230 this.on("mouseout", removeFn, this.dom);
2235 * Sets up event handlers to add and remove a css class when this element has the focus
2236 * @param {String} className
2237 * @return {Roo.Element} this
2239 addClassOnFocus : function(className){
2240 this.on("focus", function(){
2241 Roo.fly(this, '_internal').addClass(className);
2243 this.on("blur", function(){
2244 Roo.fly(this, '_internal').removeClass(className);
2249 * 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)
2250 * @param {String} className
2251 * @return {Roo.Element} this
2253 addClassOnClick : function(className){
2255 this.on("mousedown", function(){
2256 Roo.fly(dom, '_internal').addClass(className);
2257 var d = Roo.get(document);
2258 var fn = function(){
2259 Roo.fly(dom, '_internal').removeClass(className);
2260 d.removeListener("mouseup", fn);
2262 d.on("mouseup", fn);
2268 * Stops the specified event from bubbling and optionally prevents the default action
2269 * @param {String} eventName
2270 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2271 * @return {Roo.Element} this
2273 swallowEvent : function(eventName, preventDefault){
2274 var fn = function(e){
2275 e.stopPropagation();
2280 if(eventName instanceof Array){
2281 for(var i = 0, len = eventName.length; i < len; i++){
2282 this.on(eventName[i], fn);
2286 this.on(eventName, fn);
2293 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2296 * Sizes this element to its parent element's dimensions performing
2297 * neccessary box adjustments.
2298 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2299 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2300 * @return {Roo.Element} this
2302 fitToParent : function(monitorResize, targetParent) {
2303 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2304 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2305 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2308 var p = Roo.get(targetParent || this.dom.parentNode);
2309 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2310 if (monitorResize === true) {
2311 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2312 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2318 * Gets the next sibling, skipping text nodes
2319 * @return {HTMLElement} The next sibling or null
2321 getNextSibling : function(){
2322 var n = this.dom.nextSibling;
2323 while(n && n.nodeType != 1){
2330 * Gets the previous sibling, skipping text nodes
2331 * @return {HTMLElement} The previous sibling or null
2333 getPrevSibling : function(){
2334 var n = this.dom.previousSibling;
2335 while(n && n.nodeType != 1){
2336 n = n.previousSibling;
2343 * Appends the passed element(s) to this element
2344 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2345 * @return {Roo.Element} this
2347 appendChild: function(el){
2354 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2355 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2356 * automatically generated with the specified attributes.
2357 * @param {HTMLElement} insertBefore (optional) a child element of this element
2358 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2359 * @return {Roo.Element} The new child element
2361 createChild: function(config, insertBefore, returnDom){
2362 config = config || {tag:'div'};
2364 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2366 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2370 * Appends this element to the passed element
2371 * @param {String/HTMLElement/Element} el The new parent element
2372 * @return {Roo.Element} this
2374 appendTo: function(el){
2375 el = Roo.getDom(el);
2376 el.appendChild(this.dom);
2381 * Inserts this element before the passed element in the DOM
2382 * @param {String/HTMLElement/Element} el The element to insert before
2383 * @return {Roo.Element} this
2385 insertBefore: function(el){
2386 el = Roo.getDom(el);
2387 el.parentNode.insertBefore(this.dom, el);
2392 * Inserts this element after the passed element in the DOM
2393 * @param {String/HTMLElement/Element} el The element to insert after
2394 * @return {Roo.Element} this
2396 insertAfter: function(el){
2397 el = Roo.getDom(el);
2398 el.parentNode.insertBefore(this.dom, el.nextSibling);
2403 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2404 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2405 * @return {Roo.Element} The new child
2407 insertFirst: function(el, returnDom){
2409 if(typeof el == 'object' && !el.nodeType){ // dh config
2410 return this.createChild(el, this.dom.firstChild, returnDom);
2412 el = Roo.getDom(el);
2413 this.dom.insertBefore(el, this.dom.firstChild);
2414 return !returnDom ? Roo.get(el) : el;
2419 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2420 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2421 * @param {String} where (optional) 'before' or 'after' defaults to before
2422 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2423 * @return {Roo.Element} the inserted Element
2425 insertSibling: function(el, where, returnDom){
2426 where = where ? where.toLowerCase() : 'before';
2428 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2430 if(typeof el == 'object' && !el.nodeType){ // dh config
2431 if(where == 'after' && !this.dom.nextSibling){
2432 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2434 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2438 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2439 where == 'before' ? this.dom : this.dom.nextSibling);
2448 * Creates and wraps this element with another element
2449 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2450 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2451 * @return {HTMLElement/Element} The newly created wrapper element
2453 wrap: function(config, returnDom){
2455 config = {tag: "div"};
2457 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2458 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2463 * Replaces the passed element with this element
2464 * @param {String/HTMLElement/Element} el The element to replace
2465 * @return {Roo.Element} this
2467 replace: function(el){
2469 this.insertBefore(el);
2475 * Inserts an html fragment into this element
2476 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2477 * @param {String} html The HTML fragment
2478 * @param {Boolean} returnEl True to return an Roo.Element
2479 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2481 insertHtml : function(where, html, returnEl){
2482 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2483 return returnEl ? Roo.get(el) : el;
2487 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2488 * @param {Object} o The object with the attributes
2489 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2490 * @return {Roo.Element} this
2492 set : function(o, useSet){
2494 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2496 if(attr == "style" || typeof o[attr] == "function") { continue; }
2498 el.className = o["cls"];
2501 el.setAttribute(attr, o[attr]);
2508 Roo.DomHelper.applyStyles(el, o.style);
2514 * Convenience method for constructing a KeyMap
2515 * @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:
2516 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2517 * @param {Function} fn The function to call
2518 * @param {Object} scope (optional) The scope of the function
2519 * @return {Roo.KeyMap} The KeyMap created
2521 addKeyListener : function(key, fn, scope){
2523 if(typeof key != "object" || key instanceof Array){
2539 return new Roo.KeyMap(this, config);
2543 * Creates a KeyMap for this element
2544 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2545 * @return {Roo.KeyMap} The KeyMap created
2547 addKeyMap : function(config){
2548 return new Roo.KeyMap(this, config);
2552 * Returns true if this element is scrollable.
2555 isScrollable : function(){
2557 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2561 * 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().
2562 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2563 * @param {Number} value The new scroll value
2564 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2565 * @return {Element} this
2568 scrollTo : function(side, value, animate){
2569 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2571 this.dom[prop] = value;
2573 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2574 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2580 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2581 * within this element's scrollable range.
2582 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2583 * @param {Number} distance How far to scroll the element in pixels
2584 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2585 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2586 * was scrolled as far as it could go.
2588 scroll : function(direction, distance, animate){
2589 if(!this.isScrollable()){
2593 var l = el.scrollLeft, t = el.scrollTop;
2594 var w = el.scrollWidth, h = el.scrollHeight;
2595 var cw = el.clientWidth, ch = el.clientHeight;
2596 direction = direction.toLowerCase();
2597 var scrolled = false;
2598 var a = this.preanim(arguments, 2);
2603 var v = Math.min(l + distance, w-cw);
2604 this.scrollTo("left", v, a);
2611 var v = Math.max(l - distance, 0);
2612 this.scrollTo("left", v, a);
2620 var v = Math.max(t - distance, 0);
2621 this.scrollTo("top", v, a);
2629 var v = Math.min(t + distance, h-ch);
2630 this.scrollTo("top", v, a);
2639 * Translates the passed page coordinates into left/top css values for this element
2640 * @param {Number/Array} x The page x or an array containing [x, y]
2641 * @param {Number} y The page y
2642 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2644 translatePoints : function(x, y){
2645 if(typeof x == 'object' || x instanceof Array){
2648 var p = this.getStyle('position');
2649 var o = this.getXY();
2651 var l = parseInt(this.getStyle('left'), 10);
2652 var t = parseInt(this.getStyle('top'), 10);
2655 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2658 t = (p == "relative") ? 0 : this.dom.offsetTop;
2661 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2665 * Returns the current scroll position of the element.
2666 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2668 getScroll : function(){
2669 var d = this.dom, doc = document;
2670 if(d == doc || d == doc.body){
2671 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2672 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2673 return {left: l, top: t};
2675 return {left: d.scrollLeft, top: d.scrollTop};
2680 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2681 * are convert to standard 6 digit hex color.
2682 * @param {String} attr The css attribute
2683 * @param {String} defaultValue The default value to use when a valid color isn't found
2684 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2687 getColor : function(attr, defaultValue, prefix){
2688 var v = this.getStyle(attr);
2689 if(!v || v == "transparent" || v == "inherit") {
2690 return defaultValue;
2692 var color = typeof prefix == "undefined" ? "#" : prefix;
2693 if(v.substr(0, 4) == "rgb("){
2694 var rvs = v.slice(4, v.length -1).split(",");
2695 for(var i = 0; i < 3; i++){
2696 var h = parseInt(rvs[i]).toString(16);
2703 if(v.substr(0, 1) == "#"){
2705 for(var i = 1; i < 4; i++){
2706 var c = v.charAt(i);
2709 }else if(v.length == 7){
2710 color += v.substr(1);
2714 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2718 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2719 * gradient background, rounded corners and a 4-way shadow.
2720 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2721 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2722 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2723 * @return {Roo.Element} this
2725 boxWrap : function(cls){
2726 cls = cls || 'x-box';
2727 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2728 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2733 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2734 * @param {String} namespace The namespace in which to look for the attribute
2735 * @param {String} name The attribute name
2736 * @return {String} The attribute value
2738 getAttributeNS : Roo.isIE ? function(ns, name){
2740 var type = typeof d[ns+":"+name];
2741 if(type != 'undefined' && type != 'unknown'){
2742 return d[ns+":"+name];
2745 } : function(ns, name){
2747 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2752 * Sets or Returns the value the dom attribute value
2753 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2754 * @param {String} value (optional) The value to set the attribute to
2755 * @return {String} The attribute value
2757 attr : function(name){
2758 if (arguments.length > 1) {
2759 this.dom.setAttribute(name, arguments[1]);
2760 return arguments[1];
2762 if (typeof(name) == 'object') {
2763 for(var i in name) {
2764 this.attr(i, name[i]);
2770 if (!this.dom.hasAttribute(name)) {
2773 return this.dom.getAttribute(name);
2780 var ep = El.prototype;
2783 * Appends an event handler (Shorthand for addListener)
2784 * @param {String} eventName The type of event to append
2785 * @param {Function} fn The method the event invokes
2786 * @param {Object} scope (optional) The scope (this object) of the fn
2787 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2790 ep.on = ep.addListener;
2792 ep.mon = ep.addListener;
2795 * Removes an event handler from this element (shorthand for removeListener)
2796 * @param {String} eventName the type of event to remove
2797 * @param {Function} fn the method the event invokes
2798 * @return {Roo.Element} this
2801 ep.un = ep.removeListener;
2804 * true to automatically adjust width and height settings for box-model issues (default to true)
2806 ep.autoBoxAdjust = true;
2809 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2812 El.addUnits = function(v, defaultUnit){
2813 if(v === "" || v == "auto"){
2816 if(v === undefined){
2819 if(typeof v == "number" || !El.unitPattern.test(v)){
2820 return v + (defaultUnit || 'px');
2825 // special markup used throughout Roo when box wrapping elements
2826 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>';
2828 * Visibility mode constant - Use visibility to hide element
2834 * Visibility mode constant - Use display to hide element
2840 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2841 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2842 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2854 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2855 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2856 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2857 * @return {Element} The Element object
2860 El.get = function(el){
2862 if(!el){ return null; }
2863 if(typeof el == "string"){ // element id
2864 if(!(elm = document.getElementById(el))){
2867 if(ex = El.cache[el]){
2870 ex = El.cache[el] = new El(elm);
2873 }else if(el.tagName){ // dom element
2877 if(ex = El.cache[id]){
2880 ex = El.cache[id] = new El(el);
2883 }else if(el instanceof El){
2885 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2886 // catch case where it hasn't been appended
2887 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2890 }else if(el.isComposite){
2892 }else if(el instanceof Array){
2893 return El.select(el);
2894 }else if(el == document){
2895 // create a bogus element object representing the document object
2897 var f = function(){};
2898 f.prototype = El.prototype;
2900 docEl.dom = document;
2908 El.uncache = function(el){
2909 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2911 delete El.cache[a[i].id || a[i]];
2917 // Garbage collection - uncache elements/purge listeners on orphaned elements
2918 // so we don't hold a reference and cause the browser to retain them
2919 El.garbageCollect = function(){
2920 if(!Roo.enableGarbageCollector){
2921 clearInterval(El.collectorThread);
2924 for(var eid in El.cache){
2925 var el = El.cache[eid], d = el.dom;
2926 // -------------------------------------------------------
2927 // Determining what is garbage:
2928 // -------------------------------------------------------
2930 // dom node is null, definitely garbage
2931 // -------------------------------------------------------
2933 // no parentNode == direct orphan, definitely garbage
2934 // -------------------------------------------------------
2935 // !d.offsetParent && !document.getElementById(eid)
2936 // display none elements have no offsetParent so we will
2937 // also try to look it up by it's id. However, check
2938 // offsetParent first so we don't do unneeded lookups.
2939 // This enables collection of elements that are not orphans
2940 // directly, but somewhere up the line they have an orphan
2942 // -------------------------------------------------------
2943 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2944 delete El.cache[eid];
2945 if(d && Roo.enableListenerCollection){
2951 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2955 El.Flyweight = function(dom){
2958 El.Flyweight.prototype = El.prototype;
2960 El._flyweights = {};
2962 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2963 * the dom node can be overwritten by other code.
2964 * @param {String/HTMLElement} el The dom node or id
2965 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2966 * prevent conflicts (e.g. internally Roo uses "_internal")
2968 * @return {Element} The shared Element object
2970 El.fly = function(el, named){
2971 named = named || '_global';
2972 el = Roo.getDom(el);
2976 if(!El._flyweights[named]){
2977 El._flyweights[named] = new El.Flyweight();
2979 El._flyweights[named].dom = el;
2980 return El._flyweights[named];
2984 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2985 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2986 * Shorthand of {@link Roo.Element#get}
2987 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2988 * @return {Element} The Element object
2994 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2995 * the dom node can be overwritten by other code.
2996 * Shorthand of {@link Roo.Element#fly}
2997 * @param {String/HTMLElement} el The dom node or id
2998 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2999 * prevent conflicts (e.g. internally Roo uses "_internal")
3001 * @return {Element} The shared Element object
3007 // speedy lookup for elements never to box adjust
3008 var noBoxAdjust = Roo.isStrict ? {
3011 input:1, select:1, textarea:1
3013 if(Roo.isIE || Roo.isGecko){
3014 noBoxAdjust['button'] = 1;
3018 Roo.EventManager.on(window, 'unload', function(){
3020 delete El._flyweights;
3028 Roo.Element.selectorFunction = Roo.DomQuery.select;
3031 Roo.Element.select = function(selector, unique, root){
3033 if(typeof selector == "string"){
3034 els = Roo.Element.selectorFunction(selector, root);
3035 }else if(selector.length !== undefined){
3038 throw "Invalid selector";
3040 if(unique === true){
3041 return new Roo.CompositeElement(els);
3043 return new Roo.CompositeElementLite(els);
3047 * Selects elements based on the passed CSS selector to enable working on them as 1.
3048 * @param {String/Array} selector The CSS selector or an array of elements
3049 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3050 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3051 * @return {CompositeElementLite/CompositeElement}
3055 Roo.select = Roo.Element.select;