jquery.ui.position.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /*!
  2. * jQuery UI Position 1.8.23
  3. *
  4. * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
  5. * Dual licensed under the MIT or GPL Version 2 licenses.
  6. * http://jquery.org/license
  7. *
  8. * http://docs.jquery.com/UI/Position
  9. */
  10. (function( $, undefined ) {
  11. $.ui = $.ui || {};
  12. var horizontalPositions = /left|center|right/,
  13. verticalPositions = /top|center|bottom/,
  14. center = "center",
  15. support = {},
  16. _position = $.fn.position,
  17. _offset = $.fn.offset;
  18. $.fn.position = function( options ) {
  19. if ( !options || !options.of ) {
  20. return _position.apply( this, arguments );
  21. }
  22. // make a copy, we don't want to modify arguments
  23. options = $.extend( {}, options );
  24. var target = $( options.of ),
  25. targetElem = target[0],
  26. collision = ( options.collision || "flip" ).split( " " ),
  27. offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
  28. targetWidth,
  29. targetHeight,
  30. basePosition;
  31. if ( targetElem.nodeType === 9 ) {
  32. targetWidth = target.width();
  33. targetHeight = target.height();
  34. basePosition = { top: 0, left: 0 };
  35. // TODO: use $.isWindow() in 1.9
  36. } else if ( targetElem.setTimeout ) {
  37. targetWidth = target.width();
  38. targetHeight = target.height();
  39. basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
  40. } else if ( targetElem.preventDefault ) {
  41. // force left top to allow flipping
  42. options.at = "left top";
  43. targetWidth = targetHeight = 0;
  44. basePosition = { top: options.of.pageY, left: options.of.pageX };
  45. } else {
  46. targetWidth = target.outerWidth();
  47. targetHeight = target.outerHeight();
  48. basePosition = target.offset();
  49. }
  50. // force my and at to have valid horizontal and veritcal positions
  51. // if a value is missing or invalid, it will be converted to center
  52. $.each( [ "my", "at" ], function() {
  53. var pos = ( options[this] || "" ).split( " " );
  54. if ( pos.length === 1) {
  55. pos = horizontalPositions.test( pos[0] ) ?
  56. pos.concat( [center] ) :
  57. verticalPositions.test( pos[0] ) ?
  58. [ center ].concat( pos ) :
  59. [ center, center ];
  60. }
  61. pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
  62. pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
  63. options[ this ] = pos;
  64. });
  65. // normalize collision option
  66. if ( collision.length === 1 ) {
  67. collision[ 1 ] = collision[ 0 ];
  68. }
  69. // normalize offset option
  70. offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
  71. if ( offset.length === 1 ) {
  72. offset[ 1 ] = offset[ 0 ];
  73. }
  74. offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
  75. if ( options.at[0] === "right" ) {
  76. basePosition.left += targetWidth;
  77. } else if ( options.at[0] === center ) {
  78. basePosition.left += targetWidth / 2;
  79. }
  80. if ( options.at[1] === "bottom" ) {
  81. basePosition.top += targetHeight;
  82. } else if ( options.at[1] === center ) {
  83. basePosition.top += targetHeight / 2;
  84. }
  85. basePosition.left += offset[ 0 ];
  86. basePosition.top += offset[ 1 ];
  87. return this.each(function() {
  88. var elem = $( this ),
  89. elemWidth = elem.outerWidth(),
  90. elemHeight = elem.outerHeight(),
  91. marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
  92. marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
  93. collisionWidth = elemWidth + marginLeft +
  94. ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ),
  95. collisionHeight = elemHeight + marginTop +
  96. ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
  97. position = $.extend( {}, basePosition ),
  98. collisionPosition;
  99. if ( options.my[0] === "right" ) {
  100. position.left -= elemWidth;
  101. } else if ( options.my[0] === center ) {
  102. position.left -= elemWidth / 2;
  103. }
  104. if ( options.my[1] === "bottom" ) {
  105. position.top -= elemHeight;
  106. } else if ( options.my[1] === center ) {
  107. position.top -= elemHeight / 2;
  108. }
  109. // prevent fractions if jQuery version doesn't support them (see #5280)
  110. if ( !support.fractions ) {
  111. position.left = Math.round( position.left );
  112. position.top = Math.round( position.top );
  113. }
  114. collisionPosition = {
  115. left: position.left - marginLeft,
  116. top: position.top - marginTop
  117. };
  118. $.each( [ "left", "top" ], function( i, dir ) {
  119. if ( $.ui.position[ collision[i] ] ) {
  120. $.ui.position[ collision[i] ][ dir ]( position, {
  121. targetWidth: targetWidth,
  122. targetHeight: targetHeight,
  123. elemWidth: elemWidth,
  124. elemHeight: elemHeight,
  125. collisionPosition: collisionPosition,
  126. collisionWidth: collisionWidth,
  127. collisionHeight: collisionHeight,
  128. offset: offset,
  129. my: options.my,
  130. at: options.at
  131. });
  132. }
  133. });
  134. if ( $.fn.bgiframe ) {
  135. elem.bgiframe();
  136. }
  137. elem.offset( $.extend( position, { using: options.using } ) );
  138. });
  139. };
  140. $.ui.position = {
  141. fit: {
  142. left: function( position, data ) {
  143. var win = $( window ),
  144. over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
  145. position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );
  146. },
  147. top: function( position, data ) {
  148. var win = $( window ),
  149. over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
  150. position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );
  151. }
  152. },
  153. flip: {
  154. left: function( position, data ) {
  155. if ( data.at[0] === center ) {
  156. return;
  157. }
  158. var win = $( window ),
  159. over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),
  160. myOffset = data.my[ 0 ] === "left" ?
  161. -data.elemWidth :
  162. data.my[ 0 ] === "right" ?
  163. data.elemWidth :
  164. 0,
  165. atOffset = data.at[ 0 ] === "left" ?
  166. data.targetWidth :
  167. -data.targetWidth,
  168. offset = -2 * data.offset[ 0 ];
  169. position.left += data.collisionPosition.left < 0 ?
  170. myOffset + atOffset + offset :
  171. over > 0 ?
  172. myOffset + atOffset + offset :
  173. 0;
  174. },
  175. top: function( position, data ) {
  176. if ( data.at[1] === center ) {
  177. return;
  178. }
  179. var win = $( window ),
  180. over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),
  181. myOffset = data.my[ 1 ] === "top" ?
  182. -data.elemHeight :
  183. data.my[ 1 ] === "bottom" ?
  184. data.elemHeight :
  185. 0,
  186. atOffset = data.at[ 1 ] === "top" ?
  187. data.targetHeight :
  188. -data.targetHeight,
  189. offset = -2 * data.offset[ 1 ];
  190. position.top += data.collisionPosition.top < 0 ?
  191. myOffset + atOffset + offset :
  192. over > 0 ?
  193. myOffset + atOffset + offset :
  194. 0;
  195. }
  196. }
  197. };
  198. // offset setter from jQuery 1.4
  199. if ( !$.offset.setOffset ) {
  200. $.offset.setOffset = function( elem, options ) {
  201. // set position first, in-case top/left are set even on static elem
  202. if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
  203. elem.style.position = "relative";
  204. }
  205. var curElem = $( elem ),
  206. curOffset = curElem.offset(),
  207. curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
  208. curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
  209. props = {
  210. top: (options.top - curOffset.top) + curTop,
  211. left: (options.left - curOffset.left) + curLeft
  212. };
  213. if ( 'using' in options ) {
  214. options.using.call( elem, props );
  215. } else {
  216. curElem.css( props );
  217. }
  218. };
  219. $.fn.offset = function( options ) {
  220. var elem = this[ 0 ];
  221. if ( !elem || !elem.ownerDocument ) { return null; }
  222. if ( options ) {
  223. if ( $.isFunction( options ) ) {
  224. return this.each(function( i ) {
  225. $( this ).offset( options.call( this, i, $( this ).offset() ) );
  226. });
  227. }
  228. return this.each(function() {
  229. $.offset.setOffset( this, options );
  230. });
  231. }
  232. return _offset.call( this );
  233. };
  234. }
  235. // jQuery <1.4.3 uses curCSS, in 1.4.3 - 1.7.2 curCSS = css, 1.8+ only has css
  236. if ( !$.curCSS ) {
  237. $.curCSS = $.css;
  238. }
  239. // fraction support test (older versions of jQuery don't support fractions)
  240. (function () {
  241. var body = document.getElementsByTagName( "body" )[ 0 ],
  242. div = document.createElement( "div" ),
  243. testElement, testElementParent, testElementStyle, offset, offsetTotal;
  244. //Create a "fake body" for testing based on method used in jQuery.support
  245. testElement = document.createElement( body ? "div" : "body" );
  246. testElementStyle = {
  247. visibility: "hidden",
  248. width: 0,
  249. height: 0,
  250. border: 0,
  251. margin: 0,
  252. background: "none"
  253. };
  254. if ( body ) {
  255. $.extend( testElementStyle, {
  256. position: "absolute",
  257. left: "-1000px",
  258. top: "-1000px"
  259. });
  260. }
  261. for ( var i in testElementStyle ) {
  262. testElement.style[ i ] = testElementStyle[ i ];
  263. }
  264. testElement.appendChild( div );
  265. testElementParent = body || document.documentElement;
  266. testElementParent.insertBefore( testElement, testElementParent.firstChild );
  267. div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;";
  268. offset = $( div ).offset( function( _, offset ) {
  269. return offset;
  270. }).offset();
  271. testElement.innerHTML = "";
  272. testElementParent.removeChild( testElement );
  273. offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 );
  274. support.fractions = offsetTotal > 21 && offsetTotal < 22;
  275. })();
  276. }( jQuery ));