/src/offset.js
JavaScript | 283 lines | 209 code | 61 blank | 13 comment | 73 complexity | 5759b5e32c056bb52c55a4c3a5b4cbdf MD5 | raw file
Possible License(s): GPL-2.0
- (function( jQuery ) {
- var rtable = /^t(?:able|d|h)$/i,
- rroot = /^(?:body|html)$/i;
- if ( "getBoundingClientRect" in document.documentElement ) {
- jQuery.fn.offset = function( options ) {
- var elem = this[0], box;
- if ( options ) {
- return this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
- try {
- box = elem.getBoundingClientRect();
- } catch(e) {}
- var doc = elem.ownerDocument,
- docElem = doc.documentElement;
- // Make sure we're not dealing with a disconnected DOM node
- if ( !box || !jQuery.contains( docElem, elem ) ) {
- return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
- }
- var body = doc.body,
- win = getWindow(doc),
- clientTop = docElem.clientTop || body.clientTop || 0,
- clientLeft = docElem.clientLeft || body.clientLeft || 0,
- scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
- scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
- top = box.top + scrollTop - clientTop,
- left = box.left + scrollLeft - clientLeft;
- return { top: top, left: left };
- };
- } else {
- jQuery.fn.offset = function( options ) {
- var elem = this[0];
- if ( options ) {
- return this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
- var computedStyle,
- offsetParent = elem.offsetParent,
- prevOffsetParent = elem,
- doc = elem.ownerDocument,
- docElem = doc.documentElement,
- body = doc.body,
- defaultView = doc.defaultView,
- prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
- top = elem.offsetTop,
- left = elem.offsetLeft;
- while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
- if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
- break;
- }
- computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
- top -= elem.scrollTop;
- left -= elem.scrollLeft;
- if ( elem === offsetParent ) {
- top += elem.offsetTop;
- left += elem.offsetLeft;
- if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
- top += parseFloat( computedStyle.borderTopWidth ) || 0;
- left += parseFloat( computedStyle.borderLeftWidth ) || 0;
- }
- prevOffsetParent = offsetParent;
- offsetParent = elem.offsetParent;
- }
- if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
- top += parseFloat( computedStyle.borderTopWidth ) || 0;
- left += parseFloat( computedStyle.borderLeftWidth ) || 0;
- }
- prevComputedStyle = computedStyle;
- }
- if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
- top += body.offsetTop;
- left += body.offsetLeft;
- }
- if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
- top += Math.max( docElem.scrollTop, body.scrollTop );
- left += Math.max( docElem.scrollLeft, body.scrollLeft );
- }
- return { top: top, left: left };
- };
- }
- jQuery.offset = {};
- jQuery.each(
- ( "doesAddBorderForTableAndCells doesNotAddBorder " +
- "doesNotIncludeMarginInBodyOffset subtractsBorderForOverflowNotVisible " +
- "supportsFixedPosition" ).split(" "), function( i, prop ) {
- jQuery.offset[ prop ] = jQuery.support[ prop ];
- });
- jQuery.extend( jQuery.offset, {
- bodyOffset: function( body ) {
- var top = body.offsetTop,
- left = body.offsetLeft;
- if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
- top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
- left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
- }
- return { top: top, left: left };
- },
- setOffset: function( elem, options, i ) {
- var position = jQuery.css( elem, "position" );
- // set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
- var curElem = jQuery( elem ),
- curOffset = curElem.offset(),
- curCSSTop = jQuery.css( elem, "top" ),
- curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
- props = {}, curPosition = {}, curTop, curLeft;
- // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
- if ( calculatePosition ) {
- curPosition = curElem.position();
- curTop = curPosition.top;
- curLeft = curPosition.left;
- } else {
- curTop = parseFloat( curCSSTop ) || 0;
- curLeft = parseFloat( curCSSLeft ) || 0;
- }
- if ( jQuery.isFunction( options ) ) {
- options = options.call( elem, i, curOffset );
- }
- if ( options.top != null ) {
- props.top = ( options.top - curOffset.top ) + curTop;
- }
- if ( options.left != null ) {
- props.left = ( options.left - curOffset.left ) + curLeft;
- }
- if ( "using" in options ) {
- options.using.call( elem, props );
- } else {
- curElem.css( props );
- }
- }
- });
- jQuery.fn.extend({
- position: function() {
- if ( !this[0] ) {
- return null;
- }
- var elem = this[0],
- // Get *real* offsetParent
- offsetParent = this.offsetParent(),
- // Get correct offsets
- offset = this.offset(),
- parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
- // Subtract element margins
- // note: when an element has margin: auto the offsetLeft and marginLeft
- // are the same in Safari causing offset.left to incorrectly be 0
- offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
- offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
- // Add offsetParent borders
- parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
- parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
- // Subtract the two offsets
- return {
- top: offset.top - parentOffset.top,
- left: offset.left - parentOffset.left
- };
- },
- offsetParent: function() {
- return this.map(function() {
- var offsetParent = this.offsetParent || document.body;
- while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent;
- });
- }
- });
- // Create scrollLeft and scrollTop methods
- jQuery.each( ["Left", "Top"], function( i, name ) {
- var method = "scroll" + name;
- jQuery.fn[ method ] = function( val ) {
- var elem, win;
- if ( val === undefined ) {
- elem = this[ 0 ];
- if ( !elem ) {
- return null;
- }
- win = getWindow( elem );
- // Return the scroll offset
- return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
- jQuery.support.boxModel && win.document.documentElement[ method ] ||
- win.document.body[ method ] :
- elem[ method ];
- }
- // Set the scroll offset
- return this.each(function() {
- win = getWindow( this );
- if ( win ) {
- win.scrollTo(
- !i ? val : jQuery( win ).scrollLeft(),
- i ? val : jQuery( win ).scrollTop()
- );
- } else {
- this[ method ] = val;
- }
- });
- };
- });
- function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
- }
- })( jQuery );