]> source.dussan.org Git - jquery.git/commitdiff
Fixes #12749, correctly detect position() for position:fixed elements, closes gh-991
authorMerrifield, Jay <jmerrifiel@gannett.com>
Wed, 17 Oct 2012 17:40:52 +0000 (13:40 -0400)
committerMike Sherov <mike.sherov@gmail.com>
Wed, 17 Oct 2012 17:41:49 +0000 (13:41 -0400)
src/offset.js
test/unit/offset.js

index 381a42da2baa30a780d42ce4d82b5a61f6e446e5..6a2fdc9934fdac3bb02e3840819b0d83ceb76a81 100644 (file)
@@ -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 )
                };
        },
 
index 7a1d719f0f21c0c49ea24072439fa36621381093..b1cb0a3f52eee1b60f04c35c8396327677a80edd 100644 (file)
@@ -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
@@ -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 = [
@@ -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( $ ) {
@@ -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" );
@@ -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"] + " })" );
@@ -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 {
@@ -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." );