PageRenderTime 135ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/offset.js

https://github.com/Yeahuh/jquery
JavaScript | 283 lines | 209 code | 61 blank | 13 comment | 73 complexity | 5759b5e32c056bb52c55a4c3a5b4cbdf MD5 | raw file
Possible License(s): GPL-2.0
  1. (function( jQuery ) {
  2. var rtable = /^t(?:able|d|h)$/i,
  3. rroot = /^(?:body|html)$/i;
  4. if ( "getBoundingClientRect" in document.documentElement ) {
  5. jQuery.fn.offset = function( options ) {
  6. var elem = this[0], box;
  7. if ( options ) {
  8. return this.each(function( i ) {
  9. jQuery.offset.setOffset( this, options, i );
  10. });
  11. }
  12. if ( !elem || !elem.ownerDocument ) {
  13. return null;
  14. }
  15. if ( elem === elem.ownerDocument.body ) {
  16. return jQuery.offset.bodyOffset( elem );
  17. }
  18. try {
  19. box = elem.getBoundingClientRect();
  20. } catch(e) {}
  21. var doc = elem.ownerDocument,
  22. docElem = doc.documentElement;
  23. // Make sure we're not dealing with a disconnected DOM node
  24. if ( !box || !jQuery.contains( docElem, elem ) ) {
  25. return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
  26. }
  27. var body = doc.body,
  28. win = getWindow(doc),
  29. clientTop = docElem.clientTop || body.clientTop || 0,
  30. clientLeft = docElem.clientLeft || body.clientLeft || 0,
  31. scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
  32. scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
  33. top = box.top + scrollTop - clientTop,
  34. left = box.left + scrollLeft - clientLeft;
  35. return { top: top, left: left };
  36. };
  37. } else {
  38. jQuery.fn.offset = function( options ) {
  39. var elem = this[0];
  40. if ( options ) {
  41. return this.each(function( i ) {
  42. jQuery.offset.setOffset( this, options, i );
  43. });
  44. }
  45. if ( !elem || !elem.ownerDocument ) {
  46. return null;
  47. }
  48. if ( elem === elem.ownerDocument.body ) {
  49. return jQuery.offset.bodyOffset( elem );
  50. }
  51. var computedStyle,
  52. offsetParent = elem.offsetParent,
  53. prevOffsetParent = elem,
  54. doc = elem.ownerDocument,
  55. docElem = doc.documentElement,
  56. body = doc.body,
  57. defaultView = doc.defaultView,
  58. prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
  59. top = elem.offsetTop,
  60. left = elem.offsetLeft;
  61. while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
  62. if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
  63. break;
  64. }
  65. computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
  66. top -= elem.scrollTop;
  67. left -= elem.scrollLeft;
  68. if ( elem === offsetParent ) {
  69. top += elem.offsetTop;
  70. left += elem.offsetLeft;
  71. if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
  72. top += parseFloat( computedStyle.borderTopWidth ) || 0;
  73. left += parseFloat( computedStyle.borderLeftWidth ) || 0;
  74. }
  75. prevOffsetParent = offsetParent;
  76. offsetParent = elem.offsetParent;
  77. }
  78. if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
  79. top += parseFloat( computedStyle.borderTopWidth ) || 0;
  80. left += parseFloat( computedStyle.borderLeftWidth ) || 0;
  81. }
  82. prevComputedStyle = computedStyle;
  83. }
  84. if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
  85. top += body.offsetTop;
  86. left += body.offsetLeft;
  87. }
  88. if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
  89. top += Math.max( docElem.scrollTop, body.scrollTop );
  90. left += Math.max( docElem.scrollLeft, body.scrollLeft );
  91. }
  92. return { top: top, left: left };
  93. };
  94. }
  95. jQuery.offset = {};
  96. jQuery.each(
  97. ( "doesAddBorderForTableAndCells doesNotAddBorder " +
  98. "doesNotIncludeMarginInBodyOffset subtractsBorderForOverflowNotVisible " +
  99. "supportsFixedPosition" ).split(" "), function( i, prop ) {
  100. jQuery.offset[ prop ] = jQuery.support[ prop ];
  101. });
  102. jQuery.extend( jQuery.offset, {
  103. bodyOffset: function( body ) {
  104. var top = body.offsetTop,
  105. left = body.offsetLeft;
  106. if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
  107. top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
  108. left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
  109. }
  110. return { top: top, left: left };
  111. },
  112. setOffset: function( elem, options, i ) {
  113. var position = jQuery.css( elem, "position" );
  114. // set position first, in-case top/left are set even on static elem
  115. if ( position === "static" ) {
  116. elem.style.position = "relative";
  117. }
  118. var curElem = jQuery( elem ),
  119. curOffset = curElem.offset(),
  120. curCSSTop = jQuery.css( elem, "top" ),
  121. curCSSLeft = jQuery.css( elem, "left" ),
  122. calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
  123. props = {}, curPosition = {}, curTop, curLeft;
  124. // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
  125. if ( calculatePosition ) {
  126. curPosition = curElem.position();
  127. curTop = curPosition.top;
  128. curLeft = curPosition.left;
  129. } else {
  130. curTop = parseFloat( curCSSTop ) || 0;
  131. curLeft = parseFloat( curCSSLeft ) || 0;
  132. }
  133. if ( jQuery.isFunction( options ) ) {
  134. options = options.call( elem, i, curOffset );
  135. }
  136. if ( options.top != null ) {
  137. props.top = ( options.top - curOffset.top ) + curTop;
  138. }
  139. if ( options.left != null ) {
  140. props.left = ( options.left - curOffset.left ) + curLeft;
  141. }
  142. if ( "using" in options ) {
  143. options.using.call( elem, props );
  144. } else {
  145. curElem.css( props );
  146. }
  147. }
  148. });
  149. jQuery.fn.extend({
  150. position: function() {
  151. if ( !this[0] ) {
  152. return null;
  153. }
  154. var elem = this[0],
  155. // Get *real* offsetParent
  156. offsetParent = this.offsetParent(),
  157. // Get correct offsets
  158. offset = this.offset(),
  159. parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
  160. // Subtract element margins
  161. // note: when an element has margin: auto the offsetLeft and marginLeft
  162. // are the same in Safari causing offset.left to incorrectly be 0
  163. offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
  164. offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
  165. // Add offsetParent borders
  166. parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
  167. parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
  168. // Subtract the two offsets
  169. return {
  170. top: offset.top - parentOffset.top,
  171. left: offset.left - parentOffset.left
  172. };
  173. },
  174. offsetParent: function() {
  175. return this.map(function() {
  176. var offsetParent = this.offsetParent || document.body;
  177. while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
  178. offsetParent = offsetParent.offsetParent;
  179. }
  180. return offsetParent;
  181. });
  182. }
  183. });
  184. // Create scrollLeft and scrollTop methods
  185. jQuery.each( ["Left", "Top"], function( i, name ) {
  186. var method = "scroll" + name;
  187. jQuery.fn[ method ] = function( val ) {
  188. var elem, win;
  189. if ( val === undefined ) {
  190. elem = this[ 0 ];
  191. if ( !elem ) {
  192. return null;
  193. }
  194. win = getWindow( elem );
  195. // Return the scroll offset
  196. return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
  197. jQuery.support.boxModel && win.document.documentElement[ method ] ||
  198. win.document.body[ method ] :
  199. elem[ method ];
  200. }
  201. // Set the scroll offset
  202. return this.each(function() {
  203. win = getWindow( this );
  204. if ( win ) {
  205. win.scrollTo(
  206. !i ? val : jQuery( win ).scrollLeft(),
  207. i ? val : jQuery( win ).scrollTop()
  208. );
  209. } else {
  210. this[ method ] = val;
  211. }
  212. });
  213. };
  214. });
  215. function getWindow( elem ) {
  216. return jQuery.isWindow( elem ) ?
  217. elem :
  218. elem.nodeType === 9 ?
  219. elem.defaultView || elem.parentWindow :
  220. false;
  221. }
  222. })( jQuery );