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 });