css.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. define([
  2. "./core",
  3. "./var/pnum",
  4. "./core/access",
  5. "./css/var/rmargin",
  6. "./css/var/rnumnonpx",
  7. "./css/var/cssExpand",
  8. "./css/var/isHidden",
  9. "./css/var/getStyles",
  10. "./css/curCSS",
  11. "./css/defaultDisplay",
  12. "./css/addGetHookIf",
  13. "./css/support",
  14. "./data/var/data_priv",
  15. "./core/init",
  16. "./css/swap",
  17. "./core/ready",
  18. "./selector" // contains
  19. ], function( jQuery, pnum, access, rmargin, rnumnonpx, cssExpand, isHidden,
  20. getStyles, curCSS, defaultDisplay, addGetHookIf, support, data_priv ) {
  21. var
  22. // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
  23. // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
  24. rdisplayswap = /^(none|table(?!-c[ea]).+)/,
  25. rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
  26. rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
  27. cssShow = { position: "absolute", visibility: "hidden", display: "block" },
  28. cssNormalTransform = {
  29. letterSpacing: 0,
  30. fontWeight: 400
  31. },
  32. cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
  33. // return a css property mapped to a potentially vendor prefixed property
  34. function vendorPropName( style, name ) {
  35. // shortcut for names that are not vendor prefixed
  36. if ( name in style ) {
  37. return name;
  38. }
  39. // check for vendor prefixed names
  40. var capName = name[0].toUpperCase() + name.slice(1),
  41. origName = name,
  42. i = cssPrefixes.length;
  43. while ( i-- ) {
  44. name = cssPrefixes[ i ] + capName;
  45. if ( name in style ) {
  46. return name;
  47. }
  48. }
  49. return origName;
  50. }
  51. function setPositiveNumber( elem, value, subtract ) {
  52. var matches = rnumsplit.exec( value );
  53. return matches ?
  54. // Guard against undefined "subtract", e.g., when used as in cssHooks
  55. Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
  56. value;
  57. }
  58. function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  59. var i = extra === ( isBorderBox ? "border" : "content" ) ?
  60. // If we already have the right measurement, avoid augmentation
  61. 4 :
  62. // Otherwise initialize for horizontal or vertical properties
  63. name === "width" ? 1 : 0,
  64. val = 0;
  65. for ( ; i < 4; i += 2 ) {
  66. // both box models exclude margin, so add it if we want it
  67. if ( extra === "margin" ) {
  68. val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
  69. }
  70. if ( isBorderBox ) {
  71. // border-box includes padding, so remove it if we want content
  72. if ( extra === "content" ) {
  73. val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  74. }
  75. // at this point, extra isn't border nor margin, so remove border
  76. if ( extra !== "margin" ) {
  77. val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  78. }
  79. } else {
  80. // at this point, extra isn't content, so add padding
  81. val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  82. // at this point, extra isn't content nor padding, so add border
  83. if ( extra !== "padding" ) {
  84. val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  85. }
  86. }
  87. }
  88. return val;
  89. }
  90. function getWidthOrHeight( elem, name, extra ) {
  91. // Start with offset property, which is equivalent to the border-box value
  92. var valueIsBorderBox = true,
  93. val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
  94. styles = getStyles( elem ),
  95. isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
  96. // some non-html elements return undefined for offsetWidth, so check for null/undefined
  97. // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
  98. // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
  99. if ( val <= 0 || val == null ) {
  100. // Fall back to computed then uncomputed css if necessary
  101. val = curCSS( elem, name, styles );
  102. if ( val < 0 || val == null ) {
  103. val = elem.style[ name ];
  104. }
  105. // Computed unit is not pixels. Stop here and return.
  106. if ( rnumnonpx.test(val) ) {
  107. return val;
  108. }
  109. // we need the check for style in case a browser which returns unreliable values
  110. // for getComputedStyle silently falls back to the reliable elem.style
  111. valueIsBorderBox = isBorderBox &&
  112. ( support.boxSizingReliable() || val === elem.style[ name ] );
  113. // Normalize "", auto, and prepare for extra
  114. val = parseFloat( val ) || 0;
  115. }
  116. // use the active box-sizing model to add/subtract irrelevant styles
  117. return ( val +
  118. augmentWidthOrHeight(
  119. elem,
  120. name,
  121. extra || ( isBorderBox ? "border" : "content" ),
  122. valueIsBorderBox,
  123. styles
  124. )
  125. ) + "px";
  126. }
  127. function showHide( elements, show ) {
  128. var display, elem, hidden,
  129. values = [],
  130. index = 0,
  131. length = elements.length;
  132. for ( ; index < length; index++ ) {
  133. elem = elements[ index ];
  134. if ( !elem.style ) {
  135. continue;
  136. }
  137. values[ index ] = data_priv.get( elem, "olddisplay" );
  138. display = elem.style.display;
  139. if ( show ) {
  140. // Reset the inline display of this element to learn if it is
  141. // being hidden by cascaded rules or not
  142. if ( !values[ index ] && display === "none" ) {
  143. elem.style.display = "";
  144. }
  145. // Set elements which have been overridden with display: none
  146. // in a stylesheet to whatever the default browser style is
  147. // for such an element
  148. if ( elem.style.display === "" && isHidden( elem ) ) {
  149. values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
  150. }
  151. } else {
  152. if ( !values[ index ] ) {
  153. hidden = isHidden( elem );
  154. if ( display && display !== "none" || !hidden ) {
  155. data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
  156. }
  157. }
  158. }
  159. }
  160. // Set the display of most of the elements in a second loop
  161. // to avoid the constant reflow
  162. for ( index = 0; index < length; index++ ) {
  163. elem = elements[ index ];
  164. if ( !elem.style ) {
  165. continue;
  166. }
  167. if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
  168. elem.style.display = show ? values[ index ] || "" : "none";
  169. }
  170. }
  171. return elements;
  172. }
  173. jQuery.extend({
  174. // Add in style property hooks for overriding the default
  175. // behavior of getting and setting a style property
  176. cssHooks: {
  177. opacity: {
  178. get: function( elem, computed ) {
  179. if ( computed ) {
  180. // We should always get a number back from opacity
  181. var ret = curCSS( elem, "opacity" );
  182. return ret === "" ? "1" : ret;
  183. }
  184. }
  185. }
  186. },
  187. // Don't automatically add "px" to these possibly-unitless properties
  188. cssNumber: {
  189. "columnCount": true,
  190. "fillOpacity": true,
  191. "fontWeight": true,
  192. "lineHeight": true,
  193. "opacity": true,
  194. "order": true,
  195. "orphans": true,
  196. "widows": true,
  197. "zIndex": true,
  198. "zoom": true
  199. },
  200. // Add in properties whose names you wish to fix before
  201. // setting or getting the value
  202. cssProps: {
  203. // normalize float css property
  204. "float": "cssFloat"
  205. },
  206. // Get and set the style property on a DOM Node
  207. style: function( elem, name, value, extra ) {
  208. // Don't set styles on text and comment nodes
  209. if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
  210. return;
  211. }
  212. // Make sure that we're working with the right name
  213. var ret, type, hooks,
  214. origName = jQuery.camelCase( name ),
  215. style = elem.style;
  216. name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
  217. // gets hook for the prefixed version
  218. // followed by the unprefixed version
  219. hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  220. // Check if we're setting a value
  221. if ( value !== undefined ) {
  222. type = typeof value;
  223. // convert relative number strings (+= or -=) to relative numbers. #7345
  224. if ( type === "string" && (ret = rrelNum.exec( value )) ) {
  225. value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
  226. // Fixes bug #9237
  227. type = "number";
  228. }
  229. // Make sure that null and NaN values aren't set. See: #7116
  230. if ( value == null || value !== value ) {
  231. return;
  232. }
  233. // If a number was passed in, add 'px' to the (except for certain CSS properties)
  234. if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
  235. value += "px";
  236. }
  237. // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
  238. // but it would mean to define eight (for every problematic property) identical functions
  239. if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
  240. style[ name ] = "inherit";
  241. }
  242. // If a hook was provided, use that value, otherwise just set the specified value
  243. if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
  244. // Support: Chrome, Safari
  245. // Setting style to blank string required to delete "style: x !important;"
  246. style[ name ] = "";
  247. style[ name ] = value;
  248. }
  249. } else {
  250. // If a hook was provided get the non-computed value from there
  251. if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
  252. return ret;
  253. }
  254. // Otherwise just get the value from the style object
  255. return style[ name ];
  256. }
  257. },
  258. css: function( elem, name, extra, styles ) {
  259. var val, num, hooks,
  260. origName = jQuery.camelCase( name );
  261. // Make sure that we're working with the right name
  262. name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
  263. // gets hook for the prefixed version
  264. // followed by the unprefixed version
  265. hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  266. // If a hook was provided get the computed value from there
  267. if ( hooks && "get" in hooks ) {
  268. val = hooks.get( elem, true, extra );
  269. }
  270. // Otherwise, if a way to get the computed value exists, use that
  271. if ( val === undefined ) {
  272. val = curCSS( elem, name, styles );
  273. }
  274. //convert "normal" to computed value
  275. if ( val === "normal" && name in cssNormalTransform ) {
  276. val = cssNormalTransform[ name ];
  277. }
  278. // Return, converting to number if forced or a qualifier was provided and val looks numeric
  279. if ( extra === "" || extra ) {
  280. num = parseFloat( val );
  281. return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
  282. }
  283. return val;
  284. }
  285. });
  286. jQuery.each([ "height", "width" ], function( i, name ) {
  287. jQuery.cssHooks[ name ] = {
  288. get: function( elem, computed, extra ) {
  289. if ( computed ) {
  290. // certain elements can have dimension info if we invisibly show them
  291. // however, it must have a current display style that would benefit from this
  292. return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
  293. jQuery.swap( elem, cssShow, function() {
  294. return getWidthOrHeight( elem, name, extra );
  295. }) :
  296. getWidthOrHeight( elem, name, extra );
  297. }
  298. },
  299. set: function( elem, value, extra ) {
  300. var styles = extra && getStyles( elem );
  301. return setPositiveNumber( elem, value, extra ?
  302. augmentWidthOrHeight(
  303. elem,
  304. name,
  305. extra,
  306. jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
  307. styles
  308. ) : 0
  309. );
  310. }
  311. };
  312. });
  313. // Support: Android 2.3
  314. jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
  315. function( elem, computed ) {
  316. if ( computed ) {
  317. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  318. // Work around by temporarily setting element display to inline-block
  319. return jQuery.swap( elem, { "display": "inline-block" },
  320. curCSS, [ elem, "marginRight" ] );
  321. }
  322. }
  323. );
  324. // These hooks are used by animate to expand properties
  325. jQuery.each({
  326. margin: "",
  327. padding: "",
  328. border: "Width"
  329. }, function( prefix, suffix ) {
  330. jQuery.cssHooks[ prefix + suffix ] = {
  331. expand: function( value ) {
  332. var i = 0,
  333. expanded = {},
  334. // assumes a single number if not a string
  335. parts = typeof value === "string" ? value.split(" ") : [ value ];
  336. for ( ; i < 4; i++ ) {
  337. expanded[ prefix + cssExpand[ i ] + suffix ] =
  338. parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
  339. }
  340. return expanded;
  341. }
  342. };
  343. if ( !rmargin.test( prefix ) ) {
  344. jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
  345. }
  346. });
  347. jQuery.fn.extend({
  348. css: function( name, value ) {
  349. return access( this, function( elem, name, value ) {
  350. var styles, len,
  351. map = {},
  352. i = 0;
  353. if ( jQuery.isArray( name ) ) {
  354. styles = getStyles( elem );
  355. len = name.length;
  356. for ( ; i < len; i++ ) {
  357. map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
  358. }
  359. return map;
  360. }
  361. return value !== undefined ?
  362. jQuery.style( elem, name, value ) :
  363. jQuery.css( elem, name );
  364. }, name, value, arguments.length > 1 );
  365. },
  366. show: function() {
  367. return showHide( this, true );
  368. },
  369. hide: function() {
  370. return showHide( this );
  371. },
  372. toggle: function( state ) {
  373. if ( typeof state === "boolean" ) {
  374. return state ? this.show() : this.hide();
  375. }
  376. return this.each(function() {
  377. if ( isHidden( this ) ) {
  378. jQuery( this ).show();
  379. } else {
  380. jQuery( this ).hide();
  381. }
  382. });
  383. }
  384. });
  385. return jQuery;
  386. });