/**
 * @class Ext.Element
 */
Ext.Element.addMethods(function(){	
	// local style camelizing for speed
	var propCache = {},
		camelRe = /(-[a-z])/gi,
		classReCache = {},
		view = document.defaultView,
		EL = Ext.Element,	
		PADDING = "padding",
		MARGIN = "margin",
		BORDER = "border",
		LEFT = "-left",
		RIGHT = "-right",
		TOP = "-top",
		BOTTOM = "-bottom",
		WIDTH = "-width",		
		// special markup used throughout Ext when box wrapping elements	
		borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
		paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
		margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM};
		
	
	// private	
	function camelFn(m, a) {
		return a.charAt(1).toUpperCase();
	}
	
	// private (needs to be called => addStyles.call(this, sides, styles))
	function addStyles(sides, styles){
	    var val = 0;    
	    
	    Ext.each(sides.match(/\w/g), function(s) {
			if (s = parseInt(this.getStyle(styles[s]), 10)) {
				val += Math.abs(s);	     
			}
	    },
	    this);
	    return val;
	}

	function chkCache(prop) {
		return propCache[prop] || (propCache[prop] = prop.replace(camelRe, camelFn))
    }
	    
		    
		    
	return {	
		// private  ==> used by Fx  
		adjustWidth : function(width) {
			var me = this;	    
	        if(typeof width == "number" && me.autoBoxAdjust && !me.isBorderBox()){
	           width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
	           width = width < 0 ? 0 : width;
	        }
		    return width;
		},
		
		// private   ==> used by Fx 
		adjustHeight : function(height) {
			var me = this;	    
			if(typeof height == "number" && me.autoBoxAdjust && !me.isBorderBox()){
	           height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
	           height = height < 0 ? 0 : height;
	        }
		    return height;
		},
	
	
		
/** * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out. * @param {String/Array} className The CSS class to add, or an array of classes * @return {Ext.Element} this */ addClass : function(className){ var me = this; Ext.each(className, function(v) { me.dom.className += (!me.hasClass(v) && v ? " " + v : ""); }); return me; },
/** * Adds one or more CSS classes to this element and removes the same class(es) from all siblings. * @param {String/Array} className The CSS class to add, or an array of classes * @return {Ext.Element} this */ radioClass : function(className){ Ext.each(this.dom.parentNode.childNodes, function(v) { if(v.nodeType == 1) { Ext.get(v).removeClass(className); } }); return this.addClass(className); },
/** * Removes one or more CSS classes from the element. * @param {String/Array} className The CSS class to remove, or an array of classes * @return {Ext.Element} this */ removeClass : function(className){ var me = this; if (me.dom.className) { Ext.each(className, function(v) { me.dom.className = me.dom.className.replace( classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"), " "); }); } return me; },
/** * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it). * @param {String} className The CSS class to toggle * @return {Ext.Element} this */ toggleClass : function(className){ return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); },
/** * Checks if the specified CSS class exists on this element's DOM node. * @param {String} className The CSS class to check for * @return {Boolean} True if the class exists, else false */ hasClass : function(className){ return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1; },
/** * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added. * @param {String} oldClassName The CSS class to replace * @param {String} newClassName The replacement CSS class * @return {Ext.Element} this */ replaceClass : function(oldClassName, newClassName){ return this.removeClass(oldClassName).addClass(newClassName); }, isStyle : function(style, val) { // var ret = false; // style = this.getStyle(style); // Ext.each(Ext.toArray(arguments,1),function(s){ // if(style == s) return false; // stop iterating. // }); // return ret; return this.getStyle(style) == val; },
/** * Normalizes currentStyle and computedStyle. * @param {String} property The style property whose value is returned. * @return {String} The current value of the style property for this element. */ getStyle : function(){ return view && view.getComputedStyle ? function(prop){ var el = this.dom, v, cs; if(el == document) return null; prop = prop == 'float' ? 'cssFloat' : prop; return (v = el.style[prop]) ? v : (cs = view.getComputedStyle(el, "")) ? cs[chkCache(prop)] : null; } : function(prop){ var el = this.dom, m, cs; if(el == document) return null; if (prop == 'opacity') { if (el.style.filter.match) { if(m = el.style.filter.match(/alpha\(opacity=(.*)\)/i)){ var fv = parseFloat(m[1]); if(!isNaN(fv)){ return fv ? fv / 100 : 0; } } } return 1; } prop = prop == 'float' ? 'styleFloat' : prop; return el.style[prop] || ((cs = el.currentStyle) ? cs[chkCache(prop)] : null); }; }(),
/** * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values * are convert to standard 6 digit hex color. * @param {String} attr The css attribute * @param {String} defaultValue The default value to use when a valid color isn't found * @param {String} prefix (optional) defaults to #. Use an empty string when working with * color anims. */ getColor : function(attr, defaultValue, prefix){ var v = this.getStyle(attr), color = prefix || "#"; if(!v || v == "transparent" || v == "inherit") { return defaultValue; } if (/^r/.test(v)) { Ext.each(v.slice(4, v.length -1).split(","), function(s) { h = (s * 1).toString(16); color += h < 16 ? "0" + h : h; }); } else { color += v.replace("#","").replace(/^(\w)(\w)(\w)$/, "$1$1$2$2$3$3"); } return color.length > 5 ? color.toLowerCase() : defaultValue; },
/** * Wrapper for setting style properties, also takes single object parameter of multiple styles. * @param {String/Object} property The style property to be set, or an object of multiple styles. * @param {String} value (optional) The value to apply to the given property, or null if an object was passed. * @return {Ext.Element} this */ setStyle : function(prop, value){ var tmp, style, camel; if (!Ext.isObject(prop)) { tmp = {}; tmp[prop] = value; prop = tmp; } for (style in prop) { value = prop[style]; camel = chkCache(style); camel == 'opacity' ? this.setOpacity(value) : this.dom.style[camel] = value; } return this; },
/** * Set the opacity of the element * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.Element} this */ setOpacity : function(opacity, animate){ var me = this, s = me.dom.style; if(!animate || !me.anim){ if (Ext.isIE) { s.zoom = 1; s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") + (opacity == 1 ? "" : " alpha(opacity=" + opacity * 100 + ")"); } else { s.opacity = opacity; } }else{ me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn'); } return me; },
/** * Clears any opacity settings from this element. Required in some cases for IE. * @return {Ext.Element} this */ clearOpacity : function(){ var style = this.dom.style; if (window.ActiveXObject) { if(typeof style.filter == 'string' && (/alpha/i).test(style.filter)){ style.filter = ""; } } else { style.opacity = ""; style["-moz-opacity"] = ""; style["-khtml-opacity"] = ""; } return this; },
/** * Returns the offset height of the element * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding * @return {Number} The element's height */ getHeight : function(contentHeight){ var h = this.dom.offsetHeight || 0; h = !contentHeight ? h : h - this.getBorderWidth("tb") - this.getPadding("tb"); return h < 0 ? 0 : h; },
/** * Returns the offset width of the element * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding * @return {Number} The element's width */ getWidth : function(contentWidth){ var w = this.dom.offsetWidth || 0; w = !contentWidth ? w : w - this.getBorderWidth("lr") - this.getPadding("lr"); return w < 0 ? 0 : w; },
/** * Set the width of this Element. * @param {Mixed} width The new width. This may be one of:
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.Element} this */ setWidth : function(width, animate){ var me = this; width = me.adjustWidth(width); !animate || !me.anim ? me.dom.style.width = me.addUnits(width) : me.anim({width : {to : width}}, me.preanim(arguments, 1)); return me; },
/** * Set the height of this Element. * @param {Mixed} height The new height. This may be one of:
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.Element} this */ setHeight : function(height, animate){ var me = this; height = me.adjustHeight(height); !animate || !me.anim ? me.dom.style.height = me.addUnits(height) : me.anim({height : {to : height}}, me.preanim(arguments, 1)); return me; },
/** * Gets the width of the border(s) for the specified side(s) * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example, * passing lr would get the border (l)eft width + the border (r)ight width. * @return {Number} The width of the sides passed added together */ getBorderWidth : function(side){ return addStyles.call(this, side, borders); },
/** * Gets the width of the padding(s) for the specified side(s) * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example, * passing lr would get the padding (l)eft + the padding (r)ight. * @return {Number} The padding of the sides passed added together */ getPadding : function(side){ return addStyles.call(this, side, paddings); },
/** * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove * @return {Ext.Element} this */ clip : function(){ var me = this; if(!me.isClipped){ me.isClipped = true; me.originalClip = { o: me.getStyle("overflow"), x: me.getStyle("overflow-x"), y: me.getStyle("overflow-y") }; me.setStyle("overflow", "hidden"); me.setStyle("overflow-x", "hidden"); me.setStyle("overflow-y", "hidden"); } return me; },
/** * Return clipping (overflow) to original clipping before clip() was called * @return {Ext.Element} this */ unclip : function(){ var me = this; if(me.isClipped){ me.isClipped = false; var o = me.originalClip; if(o.o){me.setStyle("overflow", o.o);} if(o.x){me.setStyle("overflow-x", o.x);} if(o.y){me.setStyle("overflow-y", o.y);} } return me; }, addStyles : addStyles, margins : margins } }() );