css.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. var curCSS, iframe,
  2. // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
  3. // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
  4. rdisplayswap = /^(none|table(?!-c[ea]).+)/,
  5. rmargin = /^margin/,
  6. rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
  7. rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
  8. rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
  9. elemdisplay = { BODY: "block" },
  10. cssShow = { position: "absolute", visibility: "hidden", display: "block" },
  11. cssNormalTransform = {
  12. letterSpacing: 0,
  13. fontWeight: 400
  14. },
  15. cssExpand = [ "Top", "Right", "Bottom", "Left" ],
  16. cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
  17. // return a css property mapped to a potentially vendor prefixed property
  18. function vendorPropName( style, name ) {
  19. // shortcut for names that are not vendor prefixed
  20. if ( name in style ) {
  21. return name;
  22. }
  23. // check for vendor prefixed names
  24. var capName = name.charAt(0).toUpperCase() + name.slice(1),
  25. origName = name,
  26. i = cssPrefixes.length;
  27. while ( i-- ) {
  28. name = cssPrefixes[ i ] + capName;
  29. if ( name in style ) {
  30. return name;
  31. }
  32. }
  33. return origName;
  34. }
  35. function isHidden( elem, el ) {
  36. // isHidden might be called from jQuery#filter function;
  37. // in that case, element will be second argument
  38. elem = el || elem;
  39. return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
  40. }
  41. // NOTE: we've included the "window" in window.getComputedStyle
  42. // because jsdom on node.js will break without it.
  43. function getStyles( elem ) {
  44. return window.getComputedStyle( elem, null );
  45. }
  46. function showHide( elements, show ) {
  47. var display, elem, hidden,
  48. values = [],
  49. index = 0,
  50. length = elements.length;
  51. for ( ; index < length; index++ ) {
  52. elem = elements[ index ];
  53. if ( !elem.style ) {
  54. continue;
  55. }
  56. values[ index ] = data_priv.get( elem, "olddisplay" );
  57. display = elem.style.display;
  58. if ( show ) {
  59. // Reset the inline display of this element to learn if it is
  60. // being hidden by cascaded rules or not
  61. if ( !values[ index ] && display === "none" ) {
  62. elem.style.display = "";
  63. }
  64. // Set elements which have been overridden with display: none
  65. // in a stylesheet to whatever the default browser style is
  66. // for such an element
  67. if ( elem.style.display === "" && isHidden( elem ) ) {
  68. values[ index ] = data_priv.access( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
  69. }
  70. } else {
  71. if ( !values[ index ] ) {
  72. hidden = isHidden( elem );
  73. if ( display && display !== "none" || !hidden ) {
  74. data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") );
  75. }
  76. }
  77. }
  78. }
  79. // Set the display of most of the elements in a second loop
  80. // to avoid the constant reflow
  81. for ( index = 0; index < length; index++ ) {
  82. elem = elements[ index ];
  83. if ( !elem.style ) {
  84. continue;
  85. }
  86. if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
  87. elem.style.display = show ? values[ index ] || "" : "none";
  88. }
  89. }
  90. return elements;
  91. }
  92. jQuery.fn.extend({
  93. css: function( name, value ) {
  94. return jQuery.access( this, function( elem, name, value ) {
  95. var styles, len,
  96. map = {},
  97. i = 0;
  98. if ( jQuery.isArray( name ) ) {
  99. styles = getStyles( elem );
  100. len = name.length;
  101. for ( ; i < len; i++ ) {
  102. map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
  103. }
  104. return map;
  105. }
  106. return value !== undefined ?
  107. jQuery.style( elem, name, value ) :
  108. jQuery.css( elem, name );
  109. }, name, value, arguments.length > 1 );
  110. },
  111. show: function() {
  112. return showHide( this, true );
  113. },
  114. hide: function() {
  115. return showHide( this );
  116. },
  117. toggle: function( state ) {
  118. if ( typeof state === "boolean" ) {
  119. return state ? this.show() : this.hide();
  120. }
  121. return this.each(function() {
  122. if ( isHidden( this ) ) {
  123. jQuery( this ).show();
  124. } else {
  125. jQuery( this ).hide();
  126. }
  127. });
  128. }
  129. });
  130. jQuery.extend({
  131. // Add in style property hooks for overriding the default
  132. // behavior of getting and setting a style property
  133. cssHooks: {
  134. opacity: {
  135. get: function( elem, computed ) {
  136. if ( computed ) {
  137. // We should always get a number back from opacity
  138. var ret = curCSS( elem, "opacity" );
  139. return ret === "" ? "1" : ret;
  140. }
  141. }
  142. }
  143. },
  144. // Don't automatically add "px" to these possibly-unitless properties
  145. cssNumber: {
  146. "columnCount": true,
  147. "fillOpacity": true,
  148. "fontWeight": true,
  149. "lineHeight": true,
  150. "opacity": true,
  151. "order": true,
  152. "orphans": true,
  153. "widows": true,
  154. "zIndex": true,
  155. "zoom": true
  156. },
  157. // Add in properties whose names you wish to fix before
  158. // setting or getting the value
  159. cssProps: {
  160. // normalize float css property
  161. "float": "cssFloat"
  162. },
  163. // Get and set the style property on a DOM Node
  164. style: function( elem, name, value, extra ) {
  165. // Don't set styles on text and comment nodes
  166. if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
  167. return;
  168. }
  169. // Make sure that we're working with the right name
  170. var ret, type, hooks,
  171. origName = jQuery.camelCase( name ),
  172. style = elem.style;
  173. name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
  174. // gets hook for the prefixed version
  175. // followed by the unprefixed version
  176. hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  177. // Check if we're setting a value
  178. if ( value !== undefined ) {
  179. type = typeof value;
  180. // convert relative number strings (+= or -=) to relative numbers. #7345
  181. if ( type === "string" && (ret = rrelNum.exec( value )) ) {
  182. value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
  183. // Fixes bug #9237
  184. type = "number";
  185. }
  186. // Make sure that NaN and null values aren't set. See: #7116
  187. if ( value == null || type === "number" && isNaN( value ) ) {
  188. return;
  189. }
  190. // If a number was passed in, add 'px' to the (except for certain CSS properties)
  191. if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
  192. value += "px";
  193. }
  194. // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
  195. // but it would mean to define eight (for every problematic property) identical functions
  196. if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
  197. style[ name ] = "inherit";
  198. }
  199. // If a hook was provided, use that value, otherwise just set the specified value
  200. if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
  201. style[ name ] = value;
  202. }
  203. } else {
  204. // If a hook was provided get the non-computed value from there
  205. if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
  206. return ret;
  207. }
  208. // Otherwise just get the value from the style object
  209. return style[ name ];
  210. }
  211. },
  212. css: function( elem, name, extra, styles ) {
  213. var val, num, hooks,
  214. origName = jQuery.camelCase( name );
  215. // Make sure that we're working with the right name
  216. name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
  217. // gets hook for the prefixed version
  218. // followed by the unprefixed version
  219. hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  220. // If a hook was provided get the computed value from there
  221. if ( hooks && "get" in hooks ) {
  222. val = hooks.get( elem, true, extra );
  223. }
  224. // Otherwise, if a way to get the computed value exists, use that
  225. if ( val === undefined ) {
  226. val = curCSS( elem, name, styles );
  227. }
  228. //convert "normal" to computed value
  229. if ( val === "normal" && name in cssNormalTransform ) {
  230. val = cssNormalTransform[ name ];
  231. }
  232. // Return, converting to number if forced or a qualifier was provided and val looks numeric
  233. if ( extra === "" || extra ) {
  234. num = parseFloat( val );
  235. return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
  236. }
  237. return val;
  238. }
  239. });
  240. curCSS = function( elem, name, _computed ) {
  241. var width, minWidth, maxWidth,
  242. computed = _computed || getStyles( elem ),
  243. // Support: IE9
  244. // getPropertyValue is only needed for .css('filter') in IE9, see #12537
  245. ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
  246. style = elem.style;
  247. if ( computed ) {
  248. if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
  249. ret = jQuery.style( elem, name );
  250. }
  251. // Support: Safari 5.1
  252. // A tribute to the "awesome hack by Dean Edwards"
  253. // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
  254. // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
  255. if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
  256. // Remember the original values
  257. width = style.width;
  258. minWidth = style.minWidth;
  259. maxWidth = style.maxWidth;
  260. // Put in the new values to get a computed value out
  261. style.minWidth = style.maxWidth = style.width = ret;
  262. ret = computed.width;
  263. // Revert the changed values
  264. style.width = width;
  265. style.minWidth = minWidth;
  266. style.maxWidth = maxWidth;
  267. }
  268. }
  269. return ret;
  270. };
  271. function setPositiveNumber( elem, value, subtract ) {
  272. var matches = rnumsplit.exec( value );
  273. return matches ?
  274. // Guard against undefined "subtract", e.g., when used as in cssHooks
  275. Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
  276. value;
  277. }
  278. function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  279. var i = extra === ( isBorderBox ? "border" : "content" ) ?
  280. // If we already have the right measurement, avoid augmentation
  281. 4 :
  282. // Otherwise initialize for horizontal or vertical properties
  283. name === "width" ? 1 : 0,
  284. val = 0;
  285. for ( ; i < 4; i += 2 ) {
  286. // both box models exclude margin, so add it if we want it
  287. if ( extra === "margin" ) {
  288. val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
  289. }
  290. if ( isBorderBox ) {
  291. // border-box includes padding, so remove it if we want content
  292. if ( extra === "content" ) {
  293. val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  294. }
  295. // at this point, extra isn't border nor margin, so remove border
  296. if ( extra !== "margin" ) {
  297. val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  298. }
  299. } else {
  300. // at this point, extra isn't content, so add padding
  301. val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  302. // at this point, extra isn't content nor padding, so add border
  303. if ( extra !== "padding" ) {
  304. val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  305. }
  306. }
  307. }
  308. return val;
  309. }
  310. function getWidthOrHeight( elem, name, extra ) {
  311. // Start with offset property, which is equivalent to the border-box value
  312. var valueIsBorderBox = true,
  313. val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
  314. styles = getStyles( elem ),
  315. isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
  316. // some non-html elements return undefined for offsetWidth, so check for null/undefined
  317. // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
  318. // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
  319. if ( val <= 0 || val == null ) {
  320. // Fall back to computed then uncomputed css if necessary
  321. val = curCSS( elem, name, styles );
  322. if ( val < 0 || val == null ) {
  323. val = elem.style[ name ];
  324. }
  325. // Computed unit is not pixels. Stop here and return.
  326. if ( rnumnonpx.test(val) ) {
  327. return val;
  328. }
  329. // we need the check for style in case a browser which returns unreliable values
  330. // for getComputedStyle silently falls back to the reliable elem.style
  331. valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
  332. // Normalize "", auto, and prepare for extra
  333. val = parseFloat( val ) || 0;
  334. }
  335. // use the active box-sizing model to add/subtract irrelevant styles
  336. return ( val +
  337. augmentWidthOrHeight(
  338. elem,
  339. name,
  340. extra || ( isBorderBox ? "border" : "content" ),
  341. valueIsBorderBox,
  342. styles
  343. )
  344. ) + "px";
  345. }
  346. // Try to determine the default display value of an element
  347. function css_defaultDisplay( nodeName ) {
  348. var doc = document,
  349. display = elemdisplay[ nodeName ];
  350. if ( !display ) {
  351. display = actualDisplay( nodeName, doc );
  352. // If the simple way fails, read from inside an iframe
  353. if ( display === "none" || !display ) {
  354. // Use the already-created iframe if possible
  355. iframe = ( iframe ||
  356. jQuery("<iframe frameborder='0' width='0' height='0'/>")
  357. .css( "cssText", "display:block !important" )
  358. ).appendTo( doc.documentElement );
  359. // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
  360. doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
  361. doc.write("<!doctype html><html><body>");
  362. doc.close();
  363. display = actualDisplay( nodeName, doc );
  364. iframe.detach();
  365. }
  366. // Store the correct default display
  367. elemdisplay[ nodeName ] = display;
  368. }
  369. return display;
  370. }
  371. // Called ONLY from within css_defaultDisplay
  372. function actualDisplay( name, doc ) {
  373. var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
  374. display = jQuery.css( elem[0], "display" );
  375. elem.remove();
  376. return display;
  377. }
  378. jQuery.each([ "height", "width" ], function( i, name ) {
  379. jQuery.cssHooks[ name ] = {
  380. get: function( elem, computed, extra ) {
  381. if ( computed ) {
  382. // certain elements can have dimension info if we invisibly show them
  383. // however, it must have a current display style that would benefit from this
  384. return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
  385. jQuery.swap( elem, cssShow, function() {
  386. return getWidthOrHeight( elem, name, extra );
  387. }) :
  388. getWidthOrHeight( elem, name, extra );
  389. }
  390. },
  391. set: function( elem, value, extra ) {
  392. var styles = extra && getStyles( elem );
  393. return setPositiveNumber( elem, value, extra ?
  394. augmentWidthOrHeight(
  395. elem,
  396. name,
  397. extra,
  398. jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
  399. styles
  400. ) : 0
  401. );
  402. }
  403. };
  404. });
  405. // These hooks cannot be added until DOM ready because the support test
  406. // for it is not run until after DOM ready
  407. jQuery(function() {
  408. // Support: Android 2.3
  409. if ( !jQuery.support.reliableMarginRight ) {
  410. jQuery.cssHooks.marginRight = {
  411. get: function( elem, computed ) {
  412. if ( computed ) {
  413. // Support: Android 2.3
  414. // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  415. // Work around by temporarily setting element display to inline-block
  416. return jQuery.swap( elem, { "display": "inline-block" },
  417. curCSS, [ elem, "marginRight" ] );
  418. }
  419. }
  420. };
  421. }
  422. // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
  423. // getComputedStyle returns percent when specified for top/left/bottom/right
  424. // rather than make the css module depend on the offset module, we just check for it here
  425. if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
  426. jQuery.each( [ "top", "left" ], function( i, prop ) {
  427. jQuery.cssHooks[ prop ] = {
  428. get: function( elem, computed ) {
  429. if ( computed ) {
  430. computed = curCSS( elem, prop );
  431. // if curCSS returns percentage, fallback to offset
  432. return rnumnonpx.test( computed ) ?
  433. jQuery( elem ).position()[ prop ] + "px" :
  434. computed;
  435. }
  436. }
  437. };
  438. });
  439. }
  440. });
  441. if ( jQuery.expr && jQuery.expr.filters ) {
  442. jQuery.expr.filters.hidden = function( elem ) {
  443. // Support: Opera <= 12.12
  444. // Opera reports offsetWidths and offsetHeights less than zero on some elements
  445. return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
  446. };
  447. jQuery.expr.filters.visible = function( elem ) {
  448. return !jQuery.expr.filters.hidden( elem );
  449. };
  450. }
  451. // These hooks are used by animate to expand properties
  452. jQuery.each({
  453. margin: "",
  454. padding: "",
  455. border: "Width"
  456. }, function( prefix, suffix ) {
  457. jQuery.cssHooks[ prefix + suffix ] = {
  458. expand: function( value ) {
  459. var i = 0,
  460. expanded = {},
  461. // assumes a single number if not a string
  462. parts = typeof value === "string" ? value.split(" ") : [ value ];
  463. for ( ; i < 4; i++ ) {
  464. expanded[ prefix + cssExpand[ i ] + suffix ] =
  465. parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
  466. }
  467. return expanded;
  468. }
  469. };
  470. if ( !rmargin.test( prefix ) ) {
  471. jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
  472. }
  473. });