1 // exclude the following css properties to add px
  2 var REXCLUDE = /z-?index|font-?weight|opacity|zoom|line-?height/i,
  3 	RALPHA = /alpha\([^)]*\)/,
  4 	ROPACITY = /opacity=([^)]*)/,
  5 	RFLOAT = /float/i,
  6 	RDASH_ALPHA = /-([a-z])/ig,
  7 	RUPPER = /([A-Z])/g,
  8 	RNUMPX = /^-?\d+(?:px)?$/i,
  9 	RNUM = /^-?\d/,
 10 	WIDTH = "width",
 11 	HEIGHT = "height",
 12 	// cache check for defaultView.getComputedStyle
 13 	isGetComputedStyle = !!DOC.defaultView && !!DOC.defaultView.getComputedStyle,
 14 	isCurrentStyle = !!document.documentElement.currentStyle,
 15 	/** @private normalize float css property */
 16 	fcamelCase = function( all, letter ) {
 17 		return letter.toUpperCase();
 18 	},
 19 	styleFloat = Simples.support.cssFloat ? "cssFloat": "styleFloat";
 20 
 21 Simples.merge( /** @lends Simples */ {
 22 	/**
 23 	 * @description Used to read the current computed style of the element including width, height, innerWidth, innerHeight, offset.top, offset.left, border, etc.
 24 	 * @function
 25 	 * @param {Element} elem the element to read the somputed style off
 26 	 * @param {String} type of the attribute to read
 27 	 * @param {Boolean} extra used to determine on outerHeight, outerWidth whether to include the margin or just the border
 28 	 */
 29 	getStyle : (function( Simples ){
 30 
 31         var RWIDTH_HEIGHT = /width|height/i,
 32 			cssShow = { position: "absolute", visibility: "hidden", display:"block" },
 33 			cssWidth = [ "Left", "Right" ],
 34 			cssHeight = [ "Top", "Bottom" ];
 35 
 36 		function getWidthHeight( elem, name, extra ){
 37 			var val;
 38 			if ( elem.offsetWidth !== 0 ) {
 39 				val = returnWidthHeight( elem, name, extra );
 40 
 41 			} else {
 42 				resetCSS( elem, cssShow, function() {
 43 					val = returnWidthHeight( elem, name, extra );
 44 				});
 45 			}
 46 
 47 			return Math.max(0, Math.round(val) );
 48 		}
 49 
 50 		function returnWidthHeight( elem, name, extra ) {
 51 			var which = name === WIDTH ? cssWidth : cssHeight, 
 52 				val = name === WIDTH ? elem.offsetWidth : elem.offsetHeight;
 53 
 54 			if ( extra === "border" ) {
 55 				return val;
 56 			}
 57 
 58 			for(var i=0,l=which.length;i<l;i++){
 59 				var append = which[i];
 60 				if ( !extra ) {
 61 					val -= parseFloat(Simples.currentCSS( elem, "padding" + append, true)) || 0;
 62 				}
 63 
 64 				if ( extra === "margin" ) {
 65 					val += parseFloat(Simples.currentCSS( elem, "margin" + append, true)) || 0;
 66 
 67 				} else {
 68 					val -= parseFloat(Simples.currentCSS( elem, "border" + append + "Width", true)) || 0;
 69 				}
 70 			}
 71 
 72 			return val;
 73 		}  
 74 
 75 		function resetCSS( elem, options, callback ){
 76 			var old = {};
 77 
 78 			// Remember the old values, and insert the new ones
 79 			for ( var name in options ) {
 80 				old[ name ] = elem.style[ name ];
 81 				elem.style[ name ] = options[ name ];
 82 			}
 83 
 84 			callback.call( elem );
 85 
 86 			// Revert the old values
 87 			for ( name in options ) {
 88 				elem.style[ name ] = old[ name ];
 89 			}	
 90 		}
 91         
 92 		return function( elem, type, extra ){
 93             if( elem && RWIDTH_HEIGHT.test( type ) ){
 94 				if( type === WIDTH || type === HEIGHT ){ 
 95 					// Get window width or height
 96 					// does it walk and quack like a window?
 97 					if( "scrollTo" in elem && elem.document ){
 98 						var client = "client" + ( ( type === WIDTH ) ? "Width" : "Height" );
 99 						// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
100 						return elem.document.compatMode === "CSS1Compat" && elem.document.documentElement[ client ] || elem.document.body[ client ];
101 				
102 					// Get document width or height
103 					// is it a document
104 					} else if( elem.nodeType === 9 ){
105 						var name = ( type === WIDTH ) ? "Width" : "Height",
106 							scroll = "scroll" + name, 
107 							offset = "offset" + name;
108 				
109 						// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
110 						return Math.max(
111 							elem.documentElement[ "client" + name ],
112 							elem.body[ scroll ], elem.documentElement[ scroll ],
113 							elem.body[ offset ], elem.documentElement[ offset ]
114 						);
115 					} else {
116 						return getWidthHeight( elem, type );
117 					}
118 				} else if( type === "innerHeight" || type === "innerWidth" ){
119 					type = type === "innerHeight" ? HEIGHT : WIDTH;
120 					return getWidthHeight( elem, type, "padding" );
121 				} else if( type === "outerHeight" || type === "outerWidth" ){
122 					type = type === "outerHeight" ? HEIGHT : WIDTH;
123 					return getWidthHeight( elem, type, extra ? "margin" : "border" );
124 				}
125 				return null;
126 			} else if( elem && ( type === TOP || type === LEFT ) ){
127 				// shortcut to prevent the instantiation of another Simples object
128 				return Simples.offset( elem )[ type ];
129 			}
130 
131 			return Simples.currentCSS( elem, type );
132 		};
133 
134 	})( Simples ),
135 	/**
136 	 * @description to read the current style attribute 
137 	 * @param {Element} elem the element to read the current style attributes off 
138 	 * @param {String} name of the style atttribute to read
139 	 */	
140 	currentCSS : function(elem, name) {
141 
142 	    var ret, style = elem.style, filter;
143 
144 	    // IE uses filters for opacity
145 	    if (!Simples.support.opacity && name === OPACITY && elem.currentStyle) {
146 	        ret = ROPACITY.test( (elem.currentStyle ? elem.currentStyle.filter : elem.style.filter ) || "") ? (parseFloat(RegExp.$1) / 100) + "": "";
147 	        return ret === "" ? "1": ret;
148 	    }
149 
150 	    // Make sure we're using the right name for getting the float value
151 	    if (RFLOAT.test(name)) {
152 	        name = styleFloat;
153 	    }
154 
155 	    if (style && style[name]) {
156 	        ret = style[name];
157 
158 	    } else if (isGetComputedStyle) {
159 
160 	        // Only "float" is needed here
161 	        if (RFLOAT.test(name)) {
162 	            name = "float";
163 	        }
164 
165 	        name = name.replace(RUPPER, "-$1").toLowerCase();
166 
167 	        var defaultView = elem.ownerDocument.defaultView;
168 
169 	        if (!defaultView) {
170 	            return null;
171 	        }
172 
173 	        var computedStyle = defaultView.getComputedStyle(elem, null);
174 
175 	        if (computedStyle) {
176 	            ret = computedStyle.getPropertyValue(name);
177 	        }
178 
179 	        // We should always get a number back from opacity
180 	        if (name === OPACITY && ret === "") {
181 	            ret = "1";
182 	        }
183 
184 	    } else if (isCurrentStyle) {
185 
186 	        name = name.replace(RDASH_ALPHA, fcamelCase );
187 	        ret = elem.currentStyle && elem.currentStyle[name];
188 
189 			if ( ret === null && style && style[ name ] ) {
190 				ret = style[ name ];
191 			}
192 	        // From the awesome hack by Dean Edwards
193 	        // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
194 	        // If we're not dealing with a regular pixel number
195 	        // but a number that has a weird ending, we need to convert it to pixels
196 	        if (!RNUMPX.test(ret) && RNUM.test(ret)) {
197 	            // Remember the original values
198 	            var left = style.left,
199 				rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
200 
201 	            // Put in the new values to get a computed value out
202 	            if( rsLeft ){
203 					elem.runtimeStyle.left = elem.currentStyle.left;
204 	            }
205 	            style.left = name === "fontSize" ? "1em": (ret || 0);
206 	            ret = style.pixelLeft + "px";
207 
208 	            // Revert the changed values
209 	            style.left = left;
210 	            if ( rsLeft ) {
211 					elem.runtimeStyle.left = rsLeft;
212 	            }
213 	        }
214 	    }
215 
216 	    return ret === "" ? "auto" : ret;
217 	},
218 	/**
219 	 * @description use to set the supplied elements style attribute 
220 	 * @param {Element} elem the element to set the style attribute on
221 	 * @param {String} name the name of the attribute to set
222 	 * @param {Number|String} value to be set either a pure number 12 or string with the 12px
223 	 */	
224 	setStyle : function( elem, name, value ){                       
225 		// don't set styles on text and comment nodes
226 		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
227 			return UNDEF;
228 		}
229 
230 		// ignore negative width and height values #1599
231 		if ( (name === WIDTH || name === HEIGHT) && parseFloat(value) < 0 ) {
232 			value = UNDEF;
233 		}
234 
235 		if ( typeof value === "number" && !REXCLUDE.test(name) ) {
236 			value += "px";
237 		}
238 
239 		var style = elem.style || elem, set = value !== UNDEF;
240 
241 		// IE uses filters for opacity
242 		if ( !Simples.support.opacity && name === OPACITY ) {
243 			if ( set ) {
244 				// IE has trouble with opacity if it does not have layout
245 				// Force it by setting the zoom level
246 				style.zoom = 1;
247 
248 				// Set the alpha filter to set the opacity
249 				var opacity = parseInt( value, 10 ) + "" === "NaN" ? "" : "alpha(opacity=" + (value * 100) + ")";
250 				var filter = style.filter || Simples.currentCSS( elem, "filter" ) || "";
251 				style.filter = RALPHA.test(filter) ? filter.replace(RALPHA, opacity) : opacity;
252 			}
253 
254 			return style.filter && style.filter.indexOf("opacity=") >= 0 ? (parseFloat( ROPACITY.exec(style.filter)[1] ) / 100) + "":"";
255 		}
256 
257 		// Make sure we're using the right name for getting the float value
258 		if ( RFLOAT.test( name ) ) {
259 			name = styleFloat;
260 		}
261 
262 		name = name.replace( RDASH_ALPHA, fcamelCase); 
263 
264 		if ( set ) {
265 			// set value to empty string when null to prevent IE issue
266 			style[ name ] = value === null ? "" : value;
267 		}
268 
269 		return style[ name ];
270 	}
271 });
272 
273 Simples.extend( /** @lends Simples.fn */ {
274 	/**
275 	 * @description Used to read the current computed style of the first element or write through this.css the style atttribute, see Simples.getStyle
276 	 * @param {String} type the computed style attribute to read
277 	 * @param {Boolean} extra whether to include extra
278 	 */	
279 	style : function( type, extra ){
280 		if( !extra || typeof extra === "boolean" ){
281 			return this[0] ? Simples.getStyle( this[0], type, extra ) : null;
282 		} else {
283 			return this.css( type, extra );
284 		}
285 	},
286 	/**
287 	 * @description Used to read the current style attribute or set the current style attribute
288 	 * @param {String} name of the attribute to set
289 	 * @param {Number|String} value to be set either a pure number 12 or string with the 12px
290 	 */	
291 	css : function( name, value ){ 
292 		if( value === UNDEF && typeof name === "string" ){
293 			return Simples.currentCSS( this[0], name );  
294 		}
295 
296 		// ignore negative width and height values #1599
297 		if ( (name === WIDTH || name === HEIGHT) && parseFloat(value) < 0 ) {
298 			value = UNDEF;
299 		}
300 		
301 		var klass = Simples.getConstructor( name );
302 		if( klass === "String" && value !== UNDEF ){
303 			var i=0,l=this.length;
304 			while( i<l ){
305 				Simples.setStyle( this[i++], name, value );
306 			}
307 		} else if( klass === "Object" ) {
308 			for( var key in name ){
309 				this.css( key, name[ key ] );
310 			}
311 		}
312 		return this;
313 	}
314 });