Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixes #12749, correctly detect position() for position:fixed elements,
…closes gh-991
  • Loading branch information
Merrifield, Jay authored and mikesherov committed Oct 17, 2012
1 parent 995f816 commit 425272a
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 49 deletions.
42 changes: 24 additions & 18 deletions src/offset.js
Expand Up @@ -107,33 +107,39 @@ jQuery.offset = {
jQuery.fn.extend({

position: function() {
if ( !this[0] ) {
if ( !this[ 0 ] ) {
return;
}

var elem = this[0],
var offsetParent, offset,
parentOffset = { top: 0, left: 0 },
elem = this[ 0 ];

// Get *real* offsetParent
offsetParent = this.offsetParent(),
// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
if ( jQuery.css( elem, "position" ) === "fixed" ) {
// we assume that getBoundingClientRect is available when computed position is fixed
offset = elem.getBoundingClientRect();
} else {
// Get *real* offsetParent
offsetParent = this.offsetParent();

// Get correct offsets
offset = this.offset();
if ( !rroot.test( offsetParent[ 0 ].nodeName ) ) {
parentOffset = offsetParent.offset();
}

// Get correct offsets
offset = this.offset(),
parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
// Add offsetParent borders
parentOffset.top += parseFloat( jQuery.css( offsetParent[ 0 ], "borderTopWidth" ) ) || 0;
parentOffset.left += parseFloat( jQuery.css( offsetParent[ 0 ], "borderLeftWidth" ) ) || 0;
}

// Subtract element margins
// Subtract parent offsets and 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
top: offset.top - parentOffset.top - ( parseFloat( jQuery.css( elem, "marginTop" ) ) || 0 ),
left: offset.left - parentOffset.left - ( parseFloat( jQuery.css( elem, "marginLeft" ) ) || 0 )
};
},

Expand Down
68 changes: 37 additions & 31 deletions test/unit/offset.js
@@ -1,6 +1,27 @@
if ( jQuery.fn.offset ) {

module("offset", { teardown: moduleTeardown });
module("offset", { setup: function(){
// force a scroll value on the main window
// this insures that the results will be wrong
// if the offset method is using the scroll offset
// of the parent window
var forceScroll = jQuery("<div>").css({ "width": 2000, "height": 2000 });
// this needs to be body, because #qunit-fixture is hidden and elements inside it don't have a scrollTop
forceScroll.appendTo("body");
var checkDiv = jQuery("<div>").appendTo("#qunit-fixture")[0];

window.scrollTo( 200, 200 );
window.supportsScroll = ( document.documentElement.scrollTop || document.body.scrollTop );
window.scrollTo( 1, 1 );

checkDiv.style.position = "fixed";
checkDiv.style.top = "20px";
// safari subtracts parent border width here which is 5px
window.supportsFixedPosition = ( checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15 );
checkDiv.style.position = checkDiv.style.top = "";
jQuery( checkDiv ).remove();
forceScroll.remove();
}, teardown: moduleTeardown });

/*
Closure-compiler will roll static methods off of the jQuery object and so they will
Expand Down Expand Up @@ -33,28 +54,11 @@ test("disconnected node", function() {
equal( result.left, 0, "Check left" );
});

var supportsScroll = false;

testIframe("offset/absolute", "absolute", function($, iframe) {
expect(4);

var doc = iframe.document,
tests, forceScroll;

// force a scroll value on the main window
// this insures that the results will be wrong
// if the offset method is using the scroll offset
// of the parent window
forceScroll = jQuery("<div>").css({ "width": 2000, "height": 2000 });
forceScroll.appendTo("body");

window.scrollTo(200, 200);

if ( document.documentElement.scrollTop || document.body.scrollTop ) {
supportsScroll = true;
}

window.scrollTo(1, 1);
tests;

// get offset
tests = [
Expand All @@ -74,8 +78,6 @@ testIframe("offset/absolute", "absolute", function($, iframe) {
equal( jQuery( this["id"], doc ).position().top, this["top"], "jQuery('" + this["id"] + "').position().top" );
equal( jQuery( this["id"], doc ).position().left, this["left"], "jQuery('" + this["id"] + "').position().left" );
});

forceScroll.remove();
});

testIframe("offset/absolute", "absolute", function( $ ) {
Expand Down Expand Up @@ -293,21 +295,25 @@ testIframe("offset/static", "static", function( $ ) {
});

testIframe("offset/fixed", "fixed", function( $ ) {
expect(30);
expect(34);

var tests = [
{ "id": "#fixed-1", "top": 1001, "left": 1001 },
{ "id": "#fixed-2", "top": 1021, "left": 1021 }
{ "id": "#fixed-1", "offsetTop": 1001, "offsetLeft": 1001, "positionTop": 0, "positionLeft": 0 },
{ "id": "#fixed-2", "offsetTop": 1021, "offsetLeft": 1021, "positionTop": 20, "positionLeft": 20 }
];

jQuery.each( tests, function() {
if ( !supportsScroll ) {
if ( !window.supportsScroll ) {
ok( true, "Browser doesn't support scroll position." );
ok( true, "Browser doesn't support scroll position." );
ok( true, "Browser doesn't support scroll position." );
ok( true, "Browser doesn't support scroll position." );

} else if ( jQuery.offset.supportsFixedPosition ) {
equal( $( this["id"] ).offset().top, this["top"], "jQuery('" + this["id"] + "').offset().top" );
equal( $( this["id"] ).offset().left, this["left"], "jQuery('" + this["id"] + "').offset().left" );
} else if ( window.supportsFixedPosition ) {
equal( $( this["id"] ).offset().top, this["offsetTop"], "jQuery('" + this["id"] + "').offset().top" );
equal( $( this["id"] ).position().top, this["positionTop"], "jQuery('" + this["id"] + "').position().top" );
equal( $( this["id"] ).offset().left, this["offsetLeft"], "jQuery('" + this["id"] + "').offset().left" );
equal( $( this["id"] ).position().left, this["positionLeft"], "jQuery('" + this["id"] + "').position().left" );
} else {
// need to have same number of assertions
ok( true, "Fixed position is not supported" );
Expand All @@ -325,7 +331,7 @@ testIframe("offset/fixed", "fixed", function( $ ) {
];

jQuery.each( tests, function() {
if ( jQuery.offset.supportsFixedPosition ) {
if ( window.supportsFixedPosition ) {
$( this["id"] ).offset({ "top": this["top"], "left": this["left"] });
equal( $( this["id"] ).offset().top, this["top"], "jQuery('" + this["id"] + "').offset({ top: " + this["top"] + " })" );
equal( $( this["id"] ).offset().left, this["left"], "jQuery('" + this["id"] + "').offset({ left: " + this["left"] + " })" );
Expand All @@ -349,7 +355,7 @@ testIframe("offset/fixed", "fixed", function( $ ) {

// Bug 8316
var $noTopLeft = $("#fixed-no-top-left");
if ( jQuery.offset.supportsFixedPosition ) {
if ( window.supportsFixedPosition ) {
equal( $noTopLeft.offset().top, 1007, "Check offset top for fixed element with no top set" );
equal( $noTopLeft.offset().left, 1007, "Check offset left for fixed element with no left set" );
} else {
Expand Down Expand Up @@ -397,7 +403,7 @@ testIframe("offset/scroll", "scroll", function( $, win ) {

win.name = "test";

if ( !supportsScroll ) {
if ( !window.supportsScroll ) {
ok( true, "Browser doesn't support scroll position." );
ok( true, "Browser doesn't support scroll position." );

Expand Down

0 comments on commit 425272a

Please sign in to comment.