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)
90 var dom = typeof element == "string" ?
91 document.getElementById(element) : element;
92 if(!dom){ // invalid id/element
96 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
97 return Roo.Element.cache[id];
110 this.id = id || Roo.id(dom);
115 var El = Roo.Element;
119 * The element's default display mode (defaults to "")
122 originalDisplay : "",
125 // note this is overridden in BS version..
128 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
134 * Sets the element's visibility mode. When setVisible() is called it
135 * will use this to determine whether to set the visibility or the display property.
136 * @param visMode Element.VISIBILITY or Element.DISPLAY
137 * @return {Roo.Element} this
139 setVisibilityMode : function(visMode){
140 this.visibilityMode = visMode;
144 * Convenience method for setVisibilityMode(Element.DISPLAY)
145 * @param {String} display (optional) What to set display to when visible
146 * @return {Roo.Element} this
148 enableDisplayMode : function(display){
149 this.setVisibilityMode(El.DISPLAY);
150 if(typeof display != "undefined") { this.originalDisplay = display; }
155 * 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)
156 * @param {String} selector The simple selector to test
157 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
158 search as a number or element (defaults to 10 || document.body)
159 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
160 * @return {HTMLElement} The matching DOM node (or null if no match was found)
162 findParent : function(simpleSelector, maxDepth, returnEl){
163 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
164 maxDepth = maxDepth || 50;
165 if(typeof maxDepth != "number"){
166 stopEl = Roo.getDom(maxDepth);
169 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
170 if(dq.is(p, simpleSelector)){
171 return returnEl ? Roo.get(p) : p;
181 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
182 * @param {String} selector The simple selector to test
183 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
184 search as a number or element (defaults to 10 || document.body)
185 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
186 * @return {HTMLElement} The matching DOM node (or null if no match was found)
188 findParentNode : function(simpleSelector, maxDepth, returnEl){
189 var p = Roo.fly(this.dom.parentNode, '_internal');
190 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
194 * Looks at the scrollable parent element
196 findScrollableParent : function()
198 var overflowRegex = /(auto|scroll)/;
200 if(this.getStyle('position') === 'fixed'){
201 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
204 var excludeStaticParent = this.getStyle('position') === "absolute";
206 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
208 if (excludeStaticParent && parent.getStyle('position') === "static") {
212 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
216 if(parent.dom.nodeName.toLowerCase() == 'body'){
217 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
221 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
225 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
226 * This is a shortcut for findParentNode() that always returns an Roo.Element.
227 * @param {String} selector The simple selector to test
228 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
229 search as a number or element (defaults to 10 || document.body)
230 * @return {Roo.Element} The matching DOM node (or null if no match was found)
232 up : function(simpleSelector, maxDepth){
233 return this.findParentNode(simpleSelector, maxDepth, true);
239 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
240 * @param {String} selector The simple selector to test
241 * @return {Boolean} True if this element matches the selector, else false
243 is : function(simpleSelector){
244 return Roo.DomQuery.is(this.dom, simpleSelector);
248 * Perform animation on this element.
249 * @param {Object} args The YUI animation control args
250 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
251 * @param {Function} onComplete (optional) Function to call when animation completes
252 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
253 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
254 * @return {Roo.Element} this
256 animate : function(args, duration, onComplete, easing, animType){
257 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
262 * @private Internal animation call
264 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
265 animType = animType || 'run';
267 var anim = Roo.lib.Anim[animType](
269 (opt.duration || defaultDur) || .35,
270 (opt.easing || defaultEase) || 'easeOut',
272 Roo.callback(cb, this);
273 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
281 // private legacy anim prep
282 preanim : function(a, i){
283 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
287 * Removes worthless text nodes
288 * @param {Boolean} forceReclean (optional) By default the element
289 * keeps track if it has been cleaned already so
290 * you can call this over and over. However, if you update the element and
291 * need to force a reclean, you can pass true.
293 clean : function(forceReclean){
294 if(this.isCleaned && forceReclean !== true){
298 var d = this.dom, n = d.firstChild, ni = -1;
300 var nx = n.nextSibling;
301 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
308 this.isCleaned = true;
313 calcOffsetsTo : function(el){
316 var restorePos = false;
317 if(el.getStyle('position') == 'static'){
318 el.position('relative');
323 while(op && op != d && op.tagName != 'HTML'){
326 op = op.offsetParent;
329 el.position('static');
335 * Scrolls this element into view within the passed container.
336 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
337 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
338 * @return {Roo.Element} this
340 scrollIntoView : function(container, hscroll){
341 var c = Roo.getDom(container) || document.body;
344 var o = this.calcOffsetsTo(c),
347 b = t+el.offsetHeight,
348 r = l+el.offsetWidth;
350 var ch = c.clientHeight;
351 var ct = parseInt(c.scrollTop, 10);
352 var cl = parseInt(c.scrollLeft, 10);
354 var cr = cl + c.clientWidth;
362 if(hscroll !== false){
366 c.scrollLeft = r-c.clientWidth;
373 scrollChildIntoView : function(child, hscroll){
374 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
378 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
379 * the new height may not be available immediately.
380 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
381 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
382 * @param {Function} onComplete (optional) Function to call when animation completes
383 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
384 * @return {Roo.Element} this
386 autoHeight : function(animate, duration, onComplete, easing){
387 var oldHeight = this.getHeight();
389 this.setHeight(1); // force clipping
390 setTimeout(function(){
391 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
393 this.setHeight(height);
395 if(typeof onComplete == "function"){
399 this.setHeight(oldHeight); // restore original height
400 this.setHeight(height, animate, duration, function(){
402 if(typeof onComplete == "function") { onComplete(); }
403 }.createDelegate(this), easing);
405 }.createDelegate(this), 0);
410 * Returns true if this element is an ancestor of the passed element
411 * @param {HTMLElement/String} el The element to check
412 * @return {Boolean} True if this element is an ancestor of el, else false
414 contains : function(el){
415 if(!el){return false;}
416 return D.isAncestor(this.dom, el.dom ? el.dom : el);
420 * Checks whether the element is currently visible using both visibility and display properties.
421 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
422 * @return {Boolean} True if the element is currently visible, else false
424 isVisible : function(deep) {
425 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
426 if(deep !== true || !vis){
429 var p = this.dom.parentNode;
430 while(p && p.tagName.toLowerCase() != "body"){
431 if(!Roo.fly(p, '_isVisible').isVisible()){
440 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
441 * @param {String} selector The CSS selector
442 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
443 * @return {CompositeElement/CompositeElementLite} The composite element
445 select : function(selector, unique){
446 return El.select(selector, unique, this.dom);
450 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
451 * @param {String} selector The CSS selector
452 * @return {Array} An array of the matched nodes
454 query : function(selector, unique){
455 return Roo.DomQuery.select(selector, this.dom);
459 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
460 * @param {String} selector The CSS selector
461 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
462 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
464 child : function(selector, returnDom){
465 var n = Roo.DomQuery.selectNode(selector, this.dom);
466 return returnDom ? n : Roo.get(n);
470 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
471 * @param {String} selector The CSS selector
472 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
473 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
475 down : function(selector, returnDom){
476 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
477 return returnDom ? n : Roo.get(n);
481 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
482 * @param {String} group The group the DD object is member of
483 * @param {Object} config The DD config object
484 * @param {Object} overrides An object containing methods to override/implement on the DD object
485 * @return {Roo.dd.DD} The DD object
487 initDD : function(group, config, overrides){
488 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
489 return Roo.apply(dd, overrides);
493 * Initializes a {@link Roo.dd.DDProxy} object for this element.
494 * @param {String} group The group the DDProxy object is member of
495 * @param {Object} config The DDProxy config object
496 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
497 * @return {Roo.dd.DDProxy} The DDProxy object
499 initDDProxy : function(group, config, overrides){
500 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
501 return Roo.apply(dd, overrides);
505 * Initializes a {@link Roo.dd.DDTarget} object for this element.
506 * @param {String} group The group the DDTarget object is member of
507 * @param {Object} config The DDTarget config object
508 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
509 * @return {Roo.dd.DDTarget} The DDTarget object
511 initDDTarget : function(group, config, overrides){
512 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
513 return Roo.apply(dd, overrides);
517 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
518 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
519 * @param {Boolean} visible Whether the element is visible
520 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
521 * @return {Roo.Element} this
523 setVisible : function(visible, animate){
525 if(this.visibilityMode == El.DISPLAY){
526 this.setDisplayed(visible);
529 this.dom.style.visibility = visible ? "visible" : "hidden";
532 // closure for composites
534 var visMode = this.visibilityMode;
536 this.setOpacity(.01);
537 this.setVisible(true);
539 this.anim({opacity: { to: (visible?1:0) }},
540 this.preanim(arguments, 1),
541 null, .35, 'easeIn', function(){
543 if(visMode == El.DISPLAY){
544 dom.style.display = "none";
546 dom.style.visibility = "hidden";
548 Roo.get(dom).setOpacity(1);
556 * Returns true if display is not "none"
559 isDisplayed : function() {
560 return this.getStyle("display") != "none";
564 * Toggles the element's visibility or display, depending on visibility mode.
565 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
566 * @return {Roo.Element} this
568 toggle : function(animate){
569 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
574 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
575 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
576 * @return {Roo.Element} this
578 setDisplayed : function(value) {
579 if(typeof value == "boolean"){
580 value = value ? this.originalDisplay : "none";
582 this.setStyle("display", value);
587 * Tries to focus the element. Any exceptions are caught and ignored.
588 * @return {Roo.Element} this
598 * Tries to blur the element. Any exceptions are caught and ignored.
599 * @return {Roo.Element} this
609 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
610 * @param {String/Array} className The CSS class to add, or an array of classes
611 * @return {Roo.Element} this
613 addClass : function(className){
614 if(className instanceof Array){
615 for(var i = 0, len = className.length; i < len; i++) {
616 this.addClass(className[i]);
619 if(className && !this.hasClass(className)){
620 if (this.dom instanceof SVGElement) {
621 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
623 this.dom.className = this.dom.className + " " + className;
631 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
632 * @param {String/Array} className The CSS class to add, or an array of classes
633 * @return {Roo.Element} this
635 radioClass : function(className){
636 var siblings = this.dom.parentNode.childNodes;
637 for(var i = 0; i < siblings.length; i++) {
640 Roo.get(s).removeClass(className);
643 this.addClass(className);
648 * Removes one or more CSS classes from the element.
649 * @param {String/Array} className The CSS class to remove, or an array of classes
650 * @return {Roo.Element} this
652 removeClass : function(className){
654 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
655 if(!className || !cn){
658 if(className instanceof Array){
659 for(var i = 0, len = className.length; i < len; i++) {
660 this.removeClass(className[i]);
663 if(this.hasClass(className)){
664 var re = this.classReCache[className];
666 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
667 this.classReCache[className] = re;
669 if (this.dom instanceof SVGElement) {
670 this.dom.className.baseVal = cn.replace(re, " ");
672 this.dom.className = cn.replace(re, " ");
683 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
684 * @param {String} className The CSS class to toggle
685 * @return {Roo.Element} this
687 toggleClass : function(className){
688 if(this.hasClass(className)){
689 this.removeClass(className);
691 this.addClass(className);
697 * Checks if the specified CSS class exists on this element's DOM node.
698 * @param {String} className The CSS class to check for
699 * @return {Boolean} True if the class exists, else false
701 hasClass : function(className){
702 if (this.dom instanceof SVGElement) {
703 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
705 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
709 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
710 * @param {String} oldClassName The CSS class to replace
711 * @param {String} newClassName The replacement CSS class
712 * @return {Roo.Element} this
714 replaceClass : function(oldClassName, newClassName){
715 this.removeClass(oldClassName);
716 this.addClass(newClassName);
721 * Returns an object with properties matching the styles requested.
722 * For example, el.getStyles('color', 'font-size', 'width') might return
723 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
724 * @param {String} style1 A style name
725 * @param {String} style2 A style name
726 * @param {String} etc.
727 * @return {Object} The style object
729 getStyles : function(){
730 var a = arguments, len = a.length, r = {};
731 for(var i = 0; i < len; i++){
732 r[a[i]] = this.getStyle(a[i]);
738 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
739 * @param {String} property The style property whose value is returned.
740 * @return {String} The current value of the style property for this element.
742 getStyle : function(){
743 return view && view.getComputedStyle ?
745 var el = this.dom, v, cs, camel;
749 if(el.style && (v = el.style[prop])){
752 if(cs = view.getComputedStyle(el, "")){
753 if(!(camel = propCache[prop])){
754 camel = propCache[prop] = prop.replace(camelRe, camelFn);
761 var el = this.dom, v, cs, camel;
762 if(prop == 'opacity'){
763 if(typeof el.style.filter == 'string'){
764 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
766 var fv = parseFloat(m[1]);
768 return fv ? fv / 100 : 0;
773 }else if(prop == 'float'){
776 if(!(camel = propCache[prop])){
777 camel = propCache[prop] = prop.replace(camelRe, camelFn);
779 if(v = el.style[camel]){
782 if(cs = el.currentStyle){
790 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
791 * @param {String/Object} property The style property to be set, or an object of multiple styles.
792 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
793 * @return {Roo.Element} this
795 setStyle : function(prop, value){
796 if(typeof prop == "string"){
798 if (prop == 'float') {
799 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
804 if(!(camel = propCache[prop])){
805 camel = propCache[prop] = prop.replace(camelRe, camelFn);
808 if(camel == 'opacity') {
809 this.setOpacity(value);
811 this.dom.style[camel] = value;
814 for(var style in prop){
815 if(typeof prop[style] != "function"){
816 this.setStyle(style, prop[style]);
824 * More flexible version of {@link #setStyle} for setting style properties.
825 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
826 * a function which returns such a specification.
827 * @return {Roo.Element} this
829 applyStyles : function(style){
830 Roo.DomHelper.applyStyles(this.dom, style);
835 * 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).
836 * @return {Number} The X position of the element
839 return D.getX(this.dom);
843 * 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).
844 * @return {Number} The Y position of the element
847 return D.getY(this.dom);
851 * 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).
852 * @return {Array} The XY position of the element
855 return D.getXY(this.dom);
859 * 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).
860 * @param {Number} The X position of the element
861 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
862 * @return {Roo.Element} this
864 setX : function(x, animate){
868 this.setXY([x, this.getY()], this.preanim(arguments, 1));
874 * 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).
875 * @param {Number} The Y position of the element
876 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
877 * @return {Roo.Element} this
879 setY : function(y, animate){
883 this.setXY([this.getX(), y], this.preanim(arguments, 1));
889 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
890 * @param {String} left The left CSS property value
891 * @return {Roo.Element} this
893 setLeft : function(left){
894 this.setStyle("left", this.addUnits(left));
899 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
900 * @param {String} top The top CSS property value
901 * @return {Roo.Element} this
903 setTop : function(top){
904 this.setStyle("top", this.addUnits(top));
909 * Sets the element's CSS right style.
910 * @param {String} right The right CSS property value
911 * @return {Roo.Element} this
913 setRight : function(right){
914 this.setStyle("right", this.addUnits(right));
919 * Sets the element's CSS bottom style.
920 * @param {String} bottom The bottom CSS property value
921 * @return {Roo.Element} this
923 setBottom : function(bottom){
924 this.setStyle("bottom", this.addUnits(bottom));
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 {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
932 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
933 * @return {Roo.Element} this
935 setXY : function(pos, animate){
937 D.setXY(this.dom, pos);
939 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
945 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
946 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
947 * @param {Number} x X value for new position (coordinates are page-based)
948 * @param {Number} y Y value for new position (coordinates are page-based)
949 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
950 * @return {Roo.Element} this
952 setLocation : function(x, y, animate){
953 this.setXY([x, y], this.preanim(arguments, 2));
958 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
959 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
960 * @param {Number} x X value for new position (coordinates are page-based)
961 * @param {Number} y Y value for new position (coordinates are page-based)
962 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
963 * @return {Roo.Element} this
965 moveTo : function(x, y, animate){
966 this.setXY([x, y], this.preanim(arguments, 2));
971 * Returns the region of the given element.
972 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
973 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
975 getRegion : function(){
976 return D.getRegion(this.dom);
980 * Returns the offset height of the element
981 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
982 * @return {Number} The element's height
984 getHeight : function(contentHeight){
985 var h = this.dom.offsetHeight || 0;
986 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
990 * Returns the offset width of the element
991 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
992 * @return {Number} The element's width
994 getWidth : function(contentWidth){
995 var w = this.dom.offsetWidth || 0;
996 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
1000 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
1001 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
1002 * if a height has not been set using CSS.
1005 getComputedHeight : function(){
1006 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
1008 h = parseInt(this.getStyle('height'), 10) || 0;
1009 if(!this.isBorderBox()){
1010 h += this.getFrameWidth('tb');
1017 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
1018 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
1019 * if a width has not been set using CSS.
1022 getComputedWidth : function(){
1023 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1025 w = parseInt(this.getStyle('width'), 10) || 0;
1026 if(!this.isBorderBox()){
1027 w += this.getFrameWidth('lr');
1034 * Returns the size of the element.
1035 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1036 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1038 getSize : function(contentSize){
1039 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1043 * Returns the width and height of the viewport.
1044 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1046 getViewSize : function(){
1047 var d = this.dom, doc = document, aw = 0, ah = 0;
1048 if(d == doc || d == doc.body){
1049 return {width : D.getViewWidth(), height: D.getViewHeight()};
1052 width : d.clientWidth,
1053 height: d.clientHeight
1059 * Returns the value of the "value" attribute
1060 * @param {Boolean} asNumber true to parse the value as a number
1061 * @return {String/Number}
1063 getValue : function(asNumber){
1064 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1068 adjustWidth : function(width){
1069 if(typeof width == "number"){
1070 if(this.autoBoxAdjust && !this.isBorderBox()){
1071 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1081 adjustHeight : function(height){
1082 if(typeof height == "number"){
1083 if(this.autoBoxAdjust && !this.isBorderBox()){
1084 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1094 * Set the width of the element
1095 * @param {Number} width The new width
1096 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1097 * @return {Roo.Element} this
1099 setWidth : function(width, animate){
1100 width = this.adjustWidth(width);
1102 this.dom.style.width = this.addUnits(width);
1104 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1110 * Set the height of the element
1111 * @param {Number} height The new height
1112 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1113 * @return {Roo.Element} this
1115 setHeight : function(height, animate){
1116 height = this.adjustHeight(height);
1118 this.dom.style.height = this.addUnits(height);
1120 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1126 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1127 * @param {Number} width The new width
1128 * @param {Number} height The new height
1129 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1130 * @return {Roo.Element} this
1132 setSize : function(width, height, animate){
1133 if(typeof width == "object"){ // in case of object from getSize()
1134 height = width.height; width = width.width;
1136 width = this.adjustWidth(width); height = this.adjustHeight(height);
1138 this.dom.style.width = this.addUnits(width);
1139 this.dom.style.height = this.addUnits(height);
1141 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1147 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1148 * @param {Number} x X value for new position (coordinates are page-based)
1149 * @param {Number} y Y value for new position (coordinates are page-based)
1150 * @param {Number} width The new width
1151 * @param {Number} height The new height
1152 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1153 * @return {Roo.Element} this
1155 setBounds : function(x, y, width, height, animate){
1157 this.setSize(width, height);
1158 this.setLocation(x, y);
1160 width = this.adjustWidth(width); height = this.adjustHeight(height);
1161 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1162 this.preanim(arguments, 4), 'motion');
1168 * 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.
1169 * @param {Roo.lib.Region} region The region to fill
1170 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1171 * @return {Roo.Element} this
1173 setRegion : function(region, animate){
1174 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1179 * Appends an event handler
1181 * @param {String} eventName The type of event to append
1182 * @param {Function} fn The method the event invokes
1183 * @param {Object} scope (optional) The scope (this object) of the fn
1184 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
1186 addListener : function(eventName, fn, scope, options)
1188 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
1189 this.addListener('touchstart', this.onTapHandler, this);
1192 // we need to handle a special case where dom element is a svg element.
1193 // in this case we do not actua
1198 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
1199 if (typeof(this.listeners[eventName]) == 'undefined') {
1200 this.listeners[eventName] = new Roo.util.Event(this, eventName);
1202 this.listeners[eventName].addListener(fn, scope, options);
1207 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
1212 onTapHandler : function(event)
1214 if(!this.tapedTwice) {
1215 this.tapedTwice = true;
1217 setTimeout( function() {
1218 s.tapedTwice = false;
1222 event.preventDefault();
1223 var revent = new MouseEvent('dblclick', {
1229 this.dom.dispatchEvent(revent);
1230 //action on double tap goes below
1235 * Removes an event handler from this element
1236 * @param {String} eventName the type of event to remove
1237 * @param {Function} fn the method the event invokes
1238 * @param {Function} scope (needed for svg fake listeners)
1239 * @return {Roo.Element} this
1241 removeListener : function(eventName, fn, scope){
1242 Roo.EventManager.removeListener(this.dom, eventName, fn);
1243 if (typeof(this.listeners[eventName]) == 'undefined') {
1246 this.listeners[eventName].removeListener(fn, scope);
1251 * Removes all previous added listeners from this element
1252 * @return {Roo.Element} this
1254 removeAllListeners : function(){
1255 E.purgeElement(this.dom);
1256 this.listeners = {};
1260 relayEvent : function(eventName, observable){
1261 this.on(eventName, function(e){
1262 observable.fireEvent(eventName, e);
1268 * Set the opacity of the element
1269 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1270 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1271 * @return {Roo.Element} this
1273 setOpacity : function(opacity, animate){
1275 var s = this.dom.style;
1278 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1279 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1281 s.opacity = opacity;
1284 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1290 * Gets the left X coordinate
1291 * @param {Boolean} local True to get the local css position instead of page coordinate
1294 getLeft : function(local){
1298 return parseInt(this.getStyle("left"), 10) || 0;
1303 * Gets the right X coordinate of the element (element X position + element width)
1304 * @param {Boolean} local True to get the local css position instead of page coordinate
1307 getRight : function(local){
1309 return this.getX() + this.getWidth();
1311 return (this.getLeft(true) + this.getWidth()) || 0;
1316 * Gets the top Y coordinate
1317 * @param {Boolean} local True to get the local css position instead of page coordinate
1320 getTop : function(local) {
1324 return parseInt(this.getStyle("top"), 10) || 0;
1329 * Gets the bottom Y coordinate of the element (element Y position + element height)
1330 * @param {Boolean} local True to get the local css position instead of page coordinate
1333 getBottom : function(local){
1335 return this.getY() + this.getHeight();
1337 return (this.getTop(true) + this.getHeight()) || 0;
1342 * Initializes positioning on this element. If a desired position is not passed, it will make the
1343 * the element positioned relative IF it is not already positioned.
1344 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1345 * @param {Number} zIndex (optional) The zIndex to apply
1346 * @param {Number} x (optional) Set the page X position
1347 * @param {Number} y (optional) Set the page Y position
1349 position : function(pos, zIndex, x, y){
1351 if(this.getStyle('position') == 'static'){
1352 this.setStyle('position', 'relative');
1355 this.setStyle("position", pos);
1358 this.setStyle("z-index", zIndex);
1360 if(x !== undefined && y !== undefined){
1362 }else if(x !== undefined){
1364 }else if(y !== undefined){
1370 * Clear positioning back to the default when the document was loaded
1371 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1372 * @return {Roo.Element} this
1374 clearPositioning : function(value){
1382 "position" : "static"
1388 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1389 * snapshot before performing an update and then restoring the element.
1392 getPositioning : function(){
1393 var l = this.getStyle("left");
1394 var t = this.getStyle("top");
1396 "position" : this.getStyle("position"),
1398 "right" : l ? "" : this.getStyle("right"),
1400 "bottom" : t ? "" : this.getStyle("bottom"),
1401 "z-index" : this.getStyle("z-index")
1406 * Gets the width of the border(s) for the specified side(s)
1407 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1408 * passing lr would get the border (l)eft width + the border (r)ight width.
1409 * @return {Number} The width of the sides passed added together
1411 getBorderWidth : function(side){
1412 return this.addStyles(side, El.borders);
1416 * Gets the width of the padding(s) for the specified side(s)
1417 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1418 * passing lr would get the padding (l)eft + the padding (r)ight.
1419 * @return {Number} The padding of the sides passed added together
1421 getPadding : function(side){
1422 return this.addStyles(side, El.paddings);
1426 * Set positioning with an object returned by getPositioning().
1427 * @param {Object} posCfg
1428 * @return {Roo.Element} this
1430 setPositioning : function(pc){
1431 this.applyStyles(pc);
1432 if(pc.right == "auto"){
1433 this.dom.style.right = "";
1435 if(pc.bottom == "auto"){
1436 this.dom.style.bottom = "";
1442 fixDisplay : function(){
1443 if(this.getStyle("display") == "none"){
1444 this.setStyle("visibility", "hidden");
1445 this.setStyle("display", this.originalDisplay); // first try reverting to default
1446 if(this.getStyle("display") == "none"){ // if that fails, default to block
1447 this.setStyle("display", "block");
1453 * Quick set left and top adding default units
1454 * @param {String} left The left CSS property value
1455 * @param {String} top The top CSS property value
1456 * @return {Roo.Element} this
1458 setLeftTop : function(left, top){
1459 this.dom.style.left = this.addUnits(left);
1460 this.dom.style.top = this.addUnits(top);
1465 * Move this element relative to its current position.
1466 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1467 * @param {Number} distance How far to move the element in pixels
1468 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1469 * @return {Roo.Element} this
1471 move : function(direction, distance, animate){
1472 var xy = this.getXY();
1473 direction = direction.toLowerCase();
1477 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1481 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1486 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1491 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1498 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1499 * @return {Roo.Element} this
1502 if(!this.isClipped){
1503 this.isClipped = true;
1504 this.originalClip = {
1505 "o": this.getStyle("overflow"),
1506 "x": this.getStyle("overflow-x"),
1507 "y": this.getStyle("overflow-y")
1509 this.setStyle("overflow", "hidden");
1510 this.setStyle("overflow-x", "hidden");
1511 this.setStyle("overflow-y", "hidden");
1517 * Return clipping (overflow) to original clipping before clip() was called
1518 * @return {Roo.Element} this
1520 unclip : function(){
1522 this.isClipped = false;
1523 var o = this.originalClip;
1524 if(o.o){this.setStyle("overflow", o.o);}
1525 if(o.x){this.setStyle("overflow-x", o.x);}
1526 if(o.y){this.setStyle("overflow-y", o.y);}
1533 * Gets the x,y coordinates specified by the anchor position on the element.
1534 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
1535 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1536 * {width: (target width), height: (target height)} (defaults to the element's current size)
1537 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1538 * @return {Array} [x, y] An array containing the element's x and y coordinates
1540 getAnchorXY : function(anchor, local, s){
1541 //Passing a different size is useful for pre-calculating anchors,
1542 //especially for anchored animations that change the el size.
1544 var w, h, vp = false;
1547 if(d == document.body || d == document){
1549 w = D.getViewWidth(); h = D.getViewHeight();
1551 w = this.getWidth(); h = this.getHeight();
1554 w = s.width; h = s.height;
1556 var x = 0, y = 0, r = Math.round;
1557 switch((anchor || "tl").toLowerCase()){
1599 var sc = this.getScroll();
1600 return [x + sc.left, y + sc.top];
1602 //Add the element's offset xy
1603 var o = this.getXY();
1604 return [x+o[0], y+o[1]];
1608 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1609 * supported position values.
1610 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1611 * @param {String} position The position to align to.
1612 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1613 * @return {Array} [x, y]
1615 getAlignToXY : function(el, p, o)
1620 throw "Element.alignTo with an element that doesn't exist";
1622 var c = false; //constrain to viewport
1623 var p1 = "", p2 = "";
1630 }else if(p.indexOf("-") == -1){
1633 p = p.toLowerCase();
1634 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1636 throw "Element.alignTo with an invalid alignment " + p;
1638 p1 = m[1]; p2 = m[2]; c = !!m[3];
1640 //Subtract the aligned el's internal xy from the target's offset xy
1641 //plus custom offset to get the aligned el's new offset xy
1642 var a1 = this.getAnchorXY(p1, true);
1643 var a2 = el.getAnchorXY(p2, false);
1644 var x = a2[0] - a1[0] + o[0];
1645 var y = a2[1] - a1[1] + o[1];
1647 //constrain the aligned el to viewport if necessary
1648 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1649 // 5px of margin for ie
1650 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1652 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1653 //perpendicular to the vp border, allow the aligned el to slide on that border,
1654 //otherwise swap the aligned el to the opposite border of the target.
1655 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1656 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1657 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
1658 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1661 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1662 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1664 if((x+w) > dw + scrollX){
1665 x = swapX ? r.left-w : dw+scrollX-w;
1668 x = swapX ? r.right : scrollX;
1670 if((y+h) > dh + scrollY){
1671 y = swapY ? r.top-h : dh+scrollY-h;
1674 y = swapY ? r.bottom : scrollY;
1681 getConstrainToXY : function(){
1682 var os = {top:0, left:0, bottom:0, right: 0};
1684 return function(el, local, offsets, proposedXY){
1686 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1688 var vw, vh, vx = 0, vy = 0;
1689 if(el.dom == document.body || el.dom == document){
1690 vw = Roo.lib.Dom.getViewWidth();
1691 vh = Roo.lib.Dom.getViewHeight();
1693 vw = el.dom.clientWidth;
1694 vh = el.dom.clientHeight;
1696 var vxy = el.getXY();
1702 var s = el.getScroll();
1704 vx += offsets.left + s.left;
1705 vy += offsets.top + s.top;
1707 vw -= offsets.right;
1708 vh -= offsets.bottom;
1713 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1714 var x = xy[0], y = xy[1];
1715 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1717 // only move it if it needs it
1720 // first validate right/bottom
1729 // then make sure top/left isn't negative
1738 return moved ? [x, y] : false;
1743 adjustForConstraints : function(xy, parent, offsets){
1744 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
1748 * Aligns this element with another element relative to the specified anchor points. If the other element is the
1749 * document it aligns it to the viewport.
1750 * The position parameter is optional, and can be specified in any one of the following formats:
1752 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1753 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1754 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
1755 * deprecated in favor of the newer two anchor syntax below</i>.</li>
1756 * <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
1757 * element's anchor point, and the second value is used as the target's anchor point.</li>
1759 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
1760 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1761 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
1762 * that specified in order to enforce the viewport constraints.
1763 * Following are all of the supported anchor positions:
1766 ----- -----------------------------
1767 tl The top left corner (default)
1768 t The center of the top edge
1769 tr The top right corner
1770 l The center of the left edge
1771 c In the center of the element
1772 r The center of the right edge
1773 bl The bottom left corner
1774 b The center of the bottom edge
1775 br The bottom right corner
1779 // align el to other-el using the default positioning ("tl-bl", non-constrained)
1780 el.alignTo("other-el");
1782 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1783 el.alignTo("other-el", "tr?");
1785 // align the bottom right corner of el with the center left edge of other-el
1786 el.alignTo("other-el", "br-l?");
1788 // align the center of el with the bottom left corner of other-el and
1789 // adjust the x position by -6 pixels (and the y position by 0)
1790 el.alignTo("other-el", "c-bl", [-6, 0]);
1792 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1793 * @param {String} position The position to align to.
1794 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1795 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1796 * @return {Roo.Element} this
1798 alignTo : function(element, position, offsets, animate){
1799 var xy = this.getAlignToXY(element, position, offsets);
1800 this.setXY(xy, this.preanim(arguments, 3));
1805 * Anchors an element to another element and realigns it when the window is resized.
1806 * @param {String/HTMLElement/Roo.Element} element The element to align to.
1807 * @param {String} position The position to align to.
1808 * @param {Array} offsets (optional) Offset the positioning by [x, y]
1809 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1810 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1811 * is a number, it is used as the buffer delay (defaults to 50ms).
1812 * @param {Function} callback The function to call after the animation finishes
1813 * @return {Roo.Element} this
1815 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1816 var action = function(){
1817 this.alignTo(el, alignment, offsets, animate);
1818 Roo.callback(callback, this);
1820 Roo.EventManager.onWindowResize(action, this);
1821 var tm = typeof monitorScroll;
1822 if(tm != 'undefined'){
1823 Roo.EventManager.on(window, 'scroll', action, this,
1824 {buffer: tm == 'number' ? monitorScroll : 50});
1826 action.call(this); // align immediately
1830 * Clears any opacity settings from this element. Required in some cases for IE.
1831 * @return {Roo.Element} this
1833 clearOpacity : function(){
1834 if (window.ActiveXObject) {
1835 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1836 this.dom.style.filter = "";
1839 this.dom.style.opacity = "";
1840 this.dom.style["-moz-opacity"] = "";
1841 this.dom.style["-khtml-opacity"] = "";
1847 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1848 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1849 * @return {Roo.Element} this
1851 hide : function(animate){
1852 this.setVisible(false, this.preanim(arguments, 0));
1857 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1858 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1859 * @return {Roo.Element} this
1861 show : function(animate){
1862 this.setVisible(true, this.preanim(arguments, 0));
1867 * @private Test if size has a unit, otherwise appends the default
1869 addUnits : function(size){
1870 return Roo.Element.addUnits(size, this.defaultUnit);
1874 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1875 * @return {Roo.Element} this
1877 beginMeasure : function(){
1879 if(el.offsetWidth || el.offsetHeight){
1880 return this; // offsets work already
1883 var p = this.dom, b = document.body; // start with this element
1884 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1885 var pe = Roo.get(p);
1886 if(pe.getStyle('display') == 'none'){
1887 changed.push({el: p, visibility: pe.getStyle("visibility")});
1888 p.style.visibility = "hidden";
1889 p.style.display = "block";
1893 this._measureChanged = changed;
1899 * Restores displays to before beginMeasure was called
1900 * @return {Roo.Element} this
1902 endMeasure : function(){
1903 var changed = this._measureChanged;
1905 for(var i = 0, len = changed.length; i < len; i++) {
1907 r.el.style.visibility = r.visibility;
1908 r.el.style.display = "none";
1910 this._measureChanged = null;
1916 * Update the innerHTML of this element, optionally searching for and processing scripts
1917 * @param {String} html The new HTML
1918 * @param {Boolean} loadScripts (optional) true to look for and process scripts
1919 * @param {Function} callback For async script loading you can be noticed when the update completes
1920 * @return {Roo.Element} this
1922 update : function(html, loadScripts, callback){
1923 if(typeof html == "undefined"){
1926 if(loadScripts !== true){
1927 this.dom.innerHTML = html;
1928 if(typeof callback == "function"){
1936 html += '<span id="' + id + '"></span>';
1938 E.onAvailable(id, function(){
1939 var hd = document.getElementsByTagName("head")[0];
1940 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1941 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1942 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1945 while(match = re.exec(html)){
1946 var attrs = match[1];
1947 var srcMatch = attrs ? attrs.match(srcRe) : false;
1948 if(srcMatch && srcMatch[2]){
1949 var s = document.createElement("script");
1950 s.src = srcMatch[2];
1951 var typeMatch = attrs.match(typeRe);
1952 if(typeMatch && typeMatch[2]){
1953 s.type = typeMatch[2];
1956 }else if(match[2] && match[2].length > 0){
1957 if(window.execScript) {
1958 window.execScript(match[2]);
1966 window.eval(match[2]);
1970 var el = document.getElementById(id);
1971 if(el){el.parentNode.removeChild(el);}
1972 if(typeof callback == "function"){
1976 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1981 * Direct access to the UpdateManager update() method (takes the same parameters).
1982 * @param {String/Function} url The url for this request or a function to call to get the url
1983 * @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}
1984 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1985 * @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.
1986 * @return {Roo.Element} this
1989 var um = this.getUpdateManager();
1990 um.update.apply(um, arguments);
1995 * Gets this element's UpdateManager
1996 * @return {Roo.UpdateManager} The UpdateManager
1998 getUpdateManager : function(){
1999 if(!this.updateManager){
2000 this.updateManager = new Roo.UpdateManager(this);
2002 return this.updateManager;
2006 * Disables text selection for this element (normalized across browsers)
2007 * @return {Roo.Element} this
2009 unselectable : function(){
2010 this.dom.unselectable = "on";
2011 this.swallowEvent("selectstart", true);
2012 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
2013 this.addClass("x-unselectable");
2018 * Calculates the x, y to center this element on the screen
2019 * @return {Array} The x, y values [x, y]
2021 getCenterXY : function(){
2022 return this.getAlignToXY(document, 'c-c');
2026 * Centers the Element in either the viewport, or another Element.
2027 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
2029 center : function(centerIn){
2030 this.alignTo(centerIn || document, 'c-c');
2035 * Tests various css rules/browsers to determine if this element uses a border box
2038 isBorderBox : function(){
2039 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
2043 * Return a box {x, y, width, height} that can be used to set another elements
2044 * size/location to match this element.
2045 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
2046 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
2047 * @return {Object} box An object in the format {x, y, width, height}
2049 getBox : function(contentBox, local){
2054 var left = parseInt(this.getStyle("left"), 10) || 0;
2055 var top = parseInt(this.getStyle("top"), 10) || 0;
2058 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
2060 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
2062 var l = this.getBorderWidth("l")+this.getPadding("l");
2063 var r = this.getBorderWidth("r")+this.getPadding("r");
2064 var t = this.getBorderWidth("t")+this.getPadding("t");
2065 var b = this.getBorderWidth("b")+this.getPadding("b");
2066 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)};
2068 bx.right = bx.x + bx.width;
2069 bx.bottom = bx.y + bx.height;
2074 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2075 for more information about the sides.
2076 * @param {String} sides
2079 getFrameWidth : function(sides, onlyContentBox){
2080 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2084 * 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.
2085 * @param {Object} box The box to fill {x, y, width, height}
2086 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2087 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2088 * @return {Roo.Element} this
2090 setBox : function(box, adjust, animate){
2091 var w = box.width, h = box.height;
2092 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2093 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2094 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2096 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2101 * Forces the browser to repaint this element
2102 * @return {Roo.Element} this
2104 repaint : function(){
2106 this.addClass("x-repaint");
2107 setTimeout(function(){
2108 Roo.get(dom).removeClass("x-repaint");
2114 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2115 * then it returns the calculated width of the sides (see getPadding)
2116 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2117 * @return {Object/Number}
2119 getMargins : function(side){
2122 top: parseInt(this.getStyle("margin-top"), 10) || 0,
2123 left: parseInt(this.getStyle("margin-left"), 10) || 0,
2124 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2125 right: parseInt(this.getStyle("margin-right"), 10) || 0
2128 return this.addStyles(side, El.margins);
2133 addStyles : function(sides, styles){
2135 for(var i = 0, len = sides.length; i < len; i++){
2136 v = this.getStyle(styles[sides.charAt(i)]);
2138 w = parseInt(v, 10);
2146 * Creates a proxy element of this element
2147 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2148 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2149 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2150 * @return {Roo.Element} The new proxy element
2152 createProxy : function(config, renderTo, matchBox){
2154 renderTo = Roo.getDom(renderTo);
2156 renderTo = document.body;
2158 config = typeof config == "object" ?
2159 config : {tag : "div", cls: config};
2160 var proxy = Roo.DomHelper.append(renderTo, config, true);
2162 proxy.setBox(this.getBox());
2168 * Puts a mask over this element to disable user interaction. Requires core.css.
2169 * This method can only be applied to elements which accept child nodes.
2170 * @param {String} msg (optional) A message to display in the mask
2171 * @param {String} msgCls (optional) A css class to apply to the msg element
2172 * @return {Element} The mask element
2174 mask : function(msg, msgCls)
2176 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2177 this.setStyle("position", "relative");
2180 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2183 this.addClass("x-masked");
2184 this._mask.setDisplayed(true);
2189 while (dom && dom.style) {
2190 if (!isNaN(parseInt(dom.style.zIndex))) {
2191 z = Math.max(z, parseInt(dom.style.zIndex));
2193 dom = dom.parentNode;
2195 // if we are masking the body - then it hides everything..
2196 if (this.dom == document.body) {
2198 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2199 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2202 if(typeof msg == 'string'){
2204 this._maskMsg = Roo.DomHelper.append(this.dom, {
2205 cls: "roo-el-mask-msg",
2209 cls: 'fa fa-spinner fa-spin'
2217 var mm = this._maskMsg;
2218 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2219 if (mm.dom.lastChild) { // weird IE issue?
2220 mm.dom.lastChild.innerHTML = msg;
2222 mm.setDisplayed(true);
2224 mm.setStyle('z-index', z + 102);
2226 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2227 this._mask.setHeight(this.getHeight());
2229 this._mask.setStyle('z-index', z + 100);
2235 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2236 * it is cached for reuse.
2238 unmask : function(removeEl){
2240 if(removeEl === true){
2241 this._mask.remove();
2244 this._maskMsg.remove();
2245 delete this._maskMsg;
2248 this._mask.setDisplayed(false);
2250 this._maskMsg.setDisplayed(false);
2254 this.removeClass("x-masked");
2258 * Returns true if this element is masked
2261 isMasked : function(){
2262 return this._mask && this._mask.isVisible();
2266 * Creates an iframe shim for this element to keep selects and other windowed objects from
2268 * @return {Roo.Element} The new shim element
2270 createShim : function(){
2271 var el = document.createElement('iframe');
2272 el.frameBorder = 'no';
2273 el.className = 'roo-shim';
2274 if(Roo.isIE && Roo.isSecure){
2275 el.src = Roo.SSL_SECURE_URL;
2277 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2278 shim.autoBoxAdjust = false;
2283 * Removes this element from the DOM and deletes it from the cache
2285 remove : function(){
2286 if(this.dom.parentNode){
2287 this.dom.parentNode.removeChild(this.dom);
2289 delete El.cache[this.dom.id];
2293 * Sets up event handlers to add and remove a css class when the mouse is over this element
2294 * @param {String} className
2295 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2296 * mouseout events for children elements
2297 * @return {Roo.Element} this
2299 addClassOnOver : function(className, preventFlicker){
2300 this.on("mouseover", function(){
2301 Roo.fly(this, '_internal').addClass(className);
2303 var removeFn = function(e){
2304 if(preventFlicker !== true || !e.within(this, true)){
2305 Roo.fly(this, '_internal').removeClass(className);
2308 this.on("mouseout", removeFn, this.dom);
2313 * Sets up event handlers to add and remove a css class when this element has the focus
2314 * @param {String} className
2315 * @return {Roo.Element} this
2317 addClassOnFocus : function(className){
2318 this.on("focus", function(){
2319 Roo.fly(this, '_internal').addClass(className);
2321 this.on("blur", function(){
2322 Roo.fly(this, '_internal').removeClass(className);
2327 * 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)
2328 * @param {String} className
2329 * @return {Roo.Element} this
2331 addClassOnClick : function(className){
2333 this.on("mousedown", function(){
2334 Roo.fly(dom, '_internal').addClass(className);
2335 var d = Roo.get(document);
2336 var fn = function(){
2337 Roo.fly(dom, '_internal').removeClass(className);
2338 d.removeListener("mouseup", fn);
2340 d.on("mouseup", fn);
2346 * Stops the specified event from bubbling and optionally prevents the default action
2347 * @param {String} eventName
2348 * @param {Boolean} preventDefault (optional) true to prevent the default action too
2349 * @return {Roo.Element} this
2351 swallowEvent : function(eventName, preventDefault){
2352 var fn = function(e){
2353 e.stopPropagation();
2358 if(eventName instanceof Array){
2359 for(var i = 0, len = eventName.length; i < len; i++){
2360 this.on(eventName[i], fn);
2364 this.on(eventName, fn);
2371 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2374 * Sizes this element to its parent element's dimensions performing
2375 * neccessary box adjustments.
2376 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2377 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2378 * @return {Roo.Element} this
2380 fitToParent : function(monitorResize, targetParent) {
2381 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2382 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2383 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2386 var p = Roo.get(targetParent || this.dom.parentNode);
2387 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2388 if (monitorResize === true) {
2389 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2390 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2396 * Gets the next sibling, skipping text nodes
2397 * @return {HTMLElement} The next sibling or null
2399 getNextSibling : function(){
2400 var n = this.dom.nextSibling;
2401 while(n && n.nodeType != 1){
2408 * Gets the previous sibling, skipping text nodes
2409 * @return {HTMLElement} The previous sibling or null
2411 getPrevSibling : function(){
2412 var n = this.dom.previousSibling;
2413 while(n && n.nodeType != 1){
2414 n = n.previousSibling;
2421 * Appends the passed element(s) to this element
2422 * @param {String/HTMLElement/Array/Element/CompositeElement} el
2423 * @return {Roo.Element} this
2425 appendChild: function(el){
2432 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2433 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2434 * automatically generated with the specified attributes.
2435 * @param {HTMLElement} insertBefore (optional) a child element of this element
2436 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2437 * @return {Roo.Element} The new child element
2439 createChild: function(config, insertBefore, returnDom){
2440 config = config || {tag:'div'};
2442 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2444 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
2448 * Appends this element to the passed element
2449 * @param {String/HTMLElement/Element} el The new parent element
2450 * @return {Roo.Element} this
2452 appendTo: function(el){
2453 el = Roo.getDom(el);
2454 el.appendChild(this.dom);
2459 * Inserts this element before the passed element in the DOM
2460 * @param {String/HTMLElement/Element} el The element to insert before
2461 * @return {Roo.Element} this
2463 insertBefore: function(el){
2464 el = Roo.getDom(el);
2465 el.parentNode.insertBefore(this.dom, el);
2470 * Inserts this element after the passed element in the DOM
2471 * @param {String/HTMLElement/Element} el The element to insert after
2472 * @return {Roo.Element} this
2474 insertAfter: function(el){
2475 el = Roo.getDom(el);
2476 el.parentNode.insertBefore(this.dom, el.nextSibling);
2481 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2482 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2483 * @return {Roo.Element} The new child
2485 insertFirst: function(el, returnDom){
2487 if(typeof el == 'object' && !el.nodeType){ // dh config
2488 return this.createChild(el, this.dom.firstChild, returnDom);
2490 el = Roo.getDom(el);
2491 this.dom.insertBefore(el, this.dom.firstChild);
2492 return !returnDom ? Roo.get(el) : el;
2497 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2498 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2499 * @param {String} where (optional) 'before' or 'after' defaults to before
2500 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2501 * @return {Roo.Element} the inserted Element
2503 insertSibling: function(el, where, returnDom){
2504 where = where ? where.toLowerCase() : 'before';
2506 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2508 if(typeof el == 'object' && !el.nodeType){ // dh config
2509 if(where == 'after' && !this.dom.nextSibling){
2510 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2512 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2516 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2517 where == 'before' ? this.dom : this.dom.nextSibling);
2526 * Creates and wraps this element with another element
2527 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2528 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2529 * @return {HTMLElement/Element} The newly created wrapper element
2531 wrap: function(config, returnDom){
2533 config = {tag: "div"};
2535 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2536 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2541 * Replaces the passed element with this element
2542 * @param {String/HTMLElement/Element} el The element to replace
2543 * @return {Roo.Element} this
2545 replace: function(el){
2547 this.insertBefore(el);
2553 * Inserts an html fragment into this element
2554 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2555 * @param {String} html The HTML fragment
2556 * @param {Boolean} returnEl True to return an Roo.Element
2557 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2559 insertHtml : function(where, html, returnEl){
2560 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2561 return returnEl ? Roo.get(el) : el;
2565 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2566 * @param {Object} o The object with the attributes
2567 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2568 * @return {Roo.Element} this
2570 set : function(o, useSet){
2572 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2574 if(attr == "style" || typeof o[attr] == "function") { continue; }
2576 el.className = o["cls"];
2579 el.setAttribute(attr, o[attr]);
2586 Roo.DomHelper.applyStyles(el, o.style);
2592 * Convenience method for constructing a KeyMap
2593 * @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:
2594 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2595 * @param {Function} fn The function to call
2596 * @param {Object} scope (optional) The scope of the function
2597 * @return {Roo.KeyMap} The KeyMap created
2599 addKeyListener : function(key, fn, scope){
2601 if(typeof key != "object" || key instanceof Array){
2617 return new Roo.KeyMap(this, config);
2621 * Creates a KeyMap for this element
2622 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2623 * @return {Roo.KeyMap} The KeyMap created
2625 addKeyMap : function(config){
2626 return new Roo.KeyMap(this, config);
2630 * Returns true if this element is scrollable.
2633 isScrollable : function(){
2635 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2639 * 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().
2640 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2641 * @param {Number} value The new scroll value
2642 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2643 * @return {Element} this
2646 scrollTo : function(side, value, animate){
2647 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2649 this.dom[prop] = value;
2651 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2652 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2658 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2659 * within this element's scrollable range.
2660 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2661 * @param {Number} distance How far to scroll the element in pixels
2662 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2663 * @return {Boolean} Returns true if a scroll was triggered or false if the element
2664 * was scrolled as far as it could go.
2666 scroll : function(direction, distance, animate){
2667 if(!this.isScrollable()){
2671 var l = el.scrollLeft, t = el.scrollTop;
2672 var w = el.scrollWidth, h = el.scrollHeight;
2673 var cw = el.clientWidth, ch = el.clientHeight;
2674 direction = direction.toLowerCase();
2675 var scrolled = false;
2676 var a = this.preanim(arguments, 2);
2681 var v = Math.min(l + distance, w-cw);
2682 this.scrollTo("left", v, a);
2689 var v = Math.max(l - distance, 0);
2690 this.scrollTo("left", v, a);
2698 var v = Math.max(t - distance, 0);
2699 this.scrollTo("top", v, a);
2707 var v = Math.min(t + distance, h-ch);
2708 this.scrollTo("top", v, a);
2717 * Translates the passed page coordinates into left/top css values for this element
2718 * @param {Number/Array} x The page x or an array containing [x, y]
2719 * @param {Number} y The page y
2720 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2722 translatePoints : function(x, y){
2723 if(typeof x == 'object' || x instanceof Array){
2726 var p = this.getStyle('position');
2727 var o = this.getXY();
2729 var l = parseInt(this.getStyle('left'), 10);
2730 var t = parseInt(this.getStyle('top'), 10);
2733 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2736 t = (p == "relative") ? 0 : this.dom.offsetTop;
2739 return {left: (x - o[0] + l), top: (y - o[1] + t)};
2743 * Returns the current scroll position of the element.
2744 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2746 getScroll : function(){
2747 var d = this.dom, doc = document;
2748 if(d == doc || d == doc.body){
2749 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2750 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2751 return {left: l, top: t};
2753 return {left: d.scrollLeft, top: d.scrollTop};
2758 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2759 * are convert to standard 6 digit hex color.
2760 * @param {String} attr The css attribute
2761 * @param {String} defaultValue The default value to use when a valid color isn't found
2762 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2765 getColor : function(attr, defaultValue, prefix){
2766 var v = this.getStyle(attr);
2767 if(!v || v == "transparent" || v == "inherit") {
2768 return defaultValue;
2770 var color = typeof prefix == "undefined" ? "#" : prefix;
2771 if(v.substr(0, 4) == "rgb("){
2772 var rvs = v.slice(4, v.length -1).split(",");
2773 for(var i = 0; i < 3; i++){
2774 var h = parseInt(rvs[i]).toString(16);
2781 if(v.substr(0, 1) == "#"){
2783 for(var i = 1; i < 4; i++){
2784 var c = v.charAt(i);
2787 }else if(v.length == 7){
2788 color += v.substr(1);
2792 return(color.length > 5 ? color.toLowerCase() : defaultValue);
2796 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2797 * gradient background, rounded corners and a 4-way shadow.
2798 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2799 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2800 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2801 * @return {Roo.Element} this
2803 boxWrap : function(cls){
2804 cls = cls || 'x-box';
2805 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2806 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2811 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2812 * @param {String} namespace The namespace in which to look for the attribute
2813 * @param {String} name The attribute name
2814 * @return {String} The attribute value
2816 getAttributeNS : Roo.isIE ? function(ns, name){
2818 var type = typeof d[ns+":"+name];
2819 if(type != 'undefined' && type != 'unknown'){
2820 return d[ns+":"+name];
2823 } : function(ns, name){
2825 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2830 * Sets or Returns the value the dom attribute value
2831 * @param {String|Object} name The attribute name (or object to set multiple attributes)
2832 * @param {String} value (optional) The value to set the attribute to
2833 * @return {String} The attribute value
2835 attr : function(name){
2836 if (arguments.length > 1) {
2837 this.dom.setAttribute(name, arguments[1]);
2838 return arguments[1];
2840 if (typeof(name) == 'object') {
2841 for(var i in name) {
2842 this.attr(i, name[i]);
2848 if (!this.dom.hasAttribute(name)) {
2851 return this.dom.getAttribute(name);
2858 var ep = El.prototype;
2861 * Appends an event handler (Shorthand for addListener)
2862 * @param {String} eventName The type of event to append
2863 * @param {Function} fn The method the event invokes
2864 * @param {Object} scope (optional) The scope (this object) of the fn
2865 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
2868 ep.on = ep.addListener;
2870 ep.mon = ep.addListener;
2873 * Removes an event handler from this element (shorthand for removeListener)
2874 * @param {String} eventName the type of event to remove
2875 * @param {Function} fn the method the event invokes
2876 * @return {Roo.Element} this
2879 ep.un = ep.removeListener;
2882 * true to automatically adjust width and height settings for box-model issues (default to true)
2884 ep.autoBoxAdjust = true;
2887 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2890 El.addUnits = function(v, defaultUnit){
2891 if(v === "" || v == "auto"){
2894 if(v === undefined){
2897 if(typeof v == "number" || !El.unitPattern.test(v)){
2898 return v + (defaultUnit || 'px');
2903 // special markup used throughout Roo when box wrapping elements
2904 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>';
2906 * Visibility mode constant - Use visibility to hide element
2912 * Visibility mode constant - Use display to hide element
2918 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2919 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2920 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2932 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2933 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2934 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2935 * @return {Element} The Element object
2938 El.get = function(el){
2940 if(!el){ return null; }
2941 if(typeof el == "string"){ // element id
2942 if(!(elm = document.getElementById(el))){
2945 if(ex = El.cache[el]){
2948 ex = El.cache[el] = new El(elm);
2951 }else if(el.tagName){ // dom element
2955 if(ex = El.cache[id]){
2958 ex = El.cache[id] = new El(el);
2961 }else if(el instanceof El){
2963 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2964 // catch case where it hasn't been appended
2965 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2968 }else if(el.isComposite){
2970 }else if(el instanceof Array){
2971 return El.select(el);
2972 }else if(el == document){
2973 // create a bogus element object representing the document object
2975 var f = function(){};
2976 f.prototype = El.prototype;
2978 docEl.dom = document;
2986 El.uncache = function(el){
2987 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2989 delete El.cache[a[i].id || a[i]];
2995 // Garbage collection - uncache elements/purge listeners on orphaned elements
2996 // so we don't hold a reference and cause the browser to retain them
2997 El.garbageCollect = function(){
2998 if(!Roo.enableGarbageCollector){
2999 clearInterval(El.collectorThread);
3002 for(var eid in El.cache){
3003 var el = El.cache[eid], d = el.dom;
3004 // -------------------------------------------------------
3005 // Determining what is garbage:
3006 // -------------------------------------------------------
3008 // dom node is null, definitely garbage
3009 // -------------------------------------------------------
3011 // no parentNode == direct orphan, definitely garbage
3012 // -------------------------------------------------------
3013 // !d.offsetParent && !document.getElementById(eid)
3014 // display none elements have no offsetParent so we will
3015 // also try to look it up by it's id. However, check
3016 // offsetParent first so we don't do unneeded lookups.
3017 // This enables collection of elements that are not orphans
3018 // directly, but somewhere up the line they have an orphan
3020 // -------------------------------------------------------
3021 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
3022 delete El.cache[eid];
3023 if(d && Roo.enableListenerCollection){
3029 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
3033 El.Flyweight = function(dom){
3036 El.Flyweight.prototype = El.prototype;
3038 El._flyweights = {};
3040 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3041 * the dom node can be overwritten by other code.
3042 * @param {String/HTMLElement} el The dom node or id
3043 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3044 * prevent conflicts (e.g. internally Roo uses "_internal")
3046 * @return {Element} The shared Element object
3048 El.fly = function(el, named){
3049 named = named || '_global';
3050 el = Roo.getDom(el);
3054 if(!El._flyweights[named]){
3055 El._flyweights[named] = new El.Flyweight();
3057 El._flyweights[named].dom = el;
3058 return El._flyweights[named];
3062 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
3063 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
3064 * Shorthand of {@link Roo.Element#get}
3065 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
3066 * @return {Element} The Element object
3072 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3073 * the dom node can be overwritten by other code.
3074 * Shorthand of {@link Roo.Element#fly}
3075 * @param {String/HTMLElement} el The dom node or id
3076 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3077 * prevent conflicts (e.g. internally Roo uses "_internal")
3079 * @return {Element} The shared Element object
3085 // speedy lookup for elements never to box adjust
3086 var noBoxAdjust = Roo.isStrict ? {
3089 input:1, select:1, textarea:1
3091 if(Roo.isIE || Roo.isGecko){
3092 noBoxAdjust['button'] = 1;
3096 Roo.EventManager.on(window, 'unload', function(){
3098 delete El._flyweights;
3106 Roo.Element.selectorFunction = Roo.DomQuery.select;
3109 Roo.Element.select = function(selector, unique, root){
3111 if(typeof selector == "string"){
3112 els = Roo.Element.selectorFunction(selector, root);
3113 }else if(selector.length !== undefined){
3116 throw "Invalid selector";
3118 if(unique === true){
3119 return new Roo.CompositeElement(els);
3121 return new Roo.CompositeElementLite(els);
3125 * Selects elements based on the passed CSS selector to enable working on them as 1.
3126 * @param {String/Array} selector The CSS selector or an array of elements
3127 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3128 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3129 * @return {CompositeElementLite/CompositeElement}
3133 Roo.select = Roo.Element.select;