]> source.dussan.org Git - jquery-ui.git/commitdiff
Draggable: normalize lookups for rootNodes when to bust scroll cache. Fixes #9379...
authorMike Sherov <mike.sherov@gmail.com>
Tue, 29 Oct 2013 22:35:42 +0000 (18:35 -0400)
committerMike Sherov <mike.sherov@gmail.com>
Tue, 3 Dec 2013 15:08:12 +0000 (10:08 -0500)
Core: update scrollParent() to support all current supported browsers.

tests/unit/draggable/draggable.html
tests/unit/draggable/draggable_core.js
tests/unit/draggable/draggable_options.js
ui/jquery.ui.core.js
ui/jquery.ui.draggable.js

index dd284f2804b828d02bc10b589be78610238cf5d9..42467d2d4dfcacf657f3863e4117c63667853f81 100644 (file)
@@ -19,6 +19,9 @@
                        top: 0;
                }
                #main-forceScrollable {
+                       position: absolute;
+                       left: 0;
+                       top: 0;
                        width: 1100px;
                        height: 1100px;
                }
@@ -33,6 +36,9 @@
                        overflow-y: hidden;
                }
                #scrollParent-forceScrollable {
+                       position: absolute;
+                       left: 0;
+                       top: 0;
                        width: 1300px;
                        height: 1300px;
                }
@@ -78,7 +84,7 @@
 <div id="qunit-fixture">
        <div id="scrollParent">
                <div id="main">
-                       <div id="draggable1" style="background: green; width: 200px; height: 100px;">Relative</div>
+                       <div id="draggable1" style="background: green; width: 200px; height: 100px; position: relative; top: 0; left: 0;">Relative</div>
                        <div id="draggable2" style="background: green; width: 200px; height: 100px; position: absolute; top: 10px; left: 10px;"><span><em>Absolute</em></span></div>
                        <div id="droppable" style="background: green; width: 200px; height: 100px; position: absolute; top: 110px; left: 110px;"><span>Absolute</span></div>
                        <div id="main-forceScrollable"></div>
index 1fefb8500d16aabd72b4a173e1a19246034cca55..b8ea1993055b165b9d619274f052d76185477291 100644 (file)
@@ -136,7 +136,7 @@ test( "#6258: not following mouse when scrolled and using overflow-y: scroll", f
                });
 });
 
-test( "#9315: Draggable: jumps down with offset of scrollbar", function() {
+test( "#9315: jumps down with offset of scrollbar", function() {
        expect( 2 );
 
        var element = $( "#draggable2" ).draggable({
@@ -186,6 +186,41 @@ test( "#5009: scroll not working with parent's position fixed", function() {
        });
 });
 
+test( "#9379: Draggable: position bug in scrollable div", function() {
+       expect( 2 );
+
+       $( "#qunit-fixture" ).html( "<div id='o_9379'><div id='i_9379'></div><div id='d_9379'>a</div></div>" );
+       $( "#i_9379" ).css({ position: "absolute", width: "500px", height: "500px" });
+       $( "#o_9379" ).css({ position: "absolute", width: "300px", height: "300px" });
+       $( "#d_9379" ).css({ width: "10px", height: "10px" });
+
+       var moves = 3,
+               startValue = 0,
+               dragDelta = 20,
+               delta = 100,
+
+               // we scroll after each drag event, so subtract 1 from number of moves for expected
+               expected = delta + ( ( moves - 1 ) * dragDelta ),
+               element = $( "#d_9379" ).draggable({
+                       drag: function() {
+                               startValue += dragDelta;
+                               $( "#o_9379" ).scrollTop( startValue ).scrollLeft( startValue );
+                       },
+                       stop: function( event, ui ) {
+                               equal( ui.position.left, expected, "left position is correct when grandparent is scrolled" );
+                               equal( ui.position.top, expected, "top position is correct when grandparent is scrolled" );
+                       }
+               });
+
+       $( "#o_9379" ).css( "overflow", "auto" );
+
+       element.simulate( "drag", {
+               dy: delta,
+               dx: delta,
+               moves: moves
+       });
+});
+
 test( "#5727: draggable from iframe" , function() {
        expect( 1 );
 
index ea52eb29923a6f8a66b8fca0576bf7c101260dce..11a3c684090337806fbfc0e1f36d0ccb68359d80 100644 (file)
@@ -377,7 +377,7 @@ test( "containment, account for border", function() {
 test( "containment, default, switching after initialization", function() {
        expect( 6 );
 
-       var element = $( "#draggable1" ).draggable({ containment: false });
+       var element = $( "#draggable1" ).draggable({ containment: false, scroll: false });
 
        TestHelpers.draggable.testDrag( element, element, -100, -100, -100, -100, "containment: default" );
 
@@ -692,7 +692,7 @@ test( "helper, default, switching after initialization", function() {
                                                                scroll: false
                                                        });
 
-                                               if ( scrollElements.length === 1 && scrollElements[ 1 ] === "#scrollParent" ) {
+                                               if ( scrollElements.length === 1 && scrollElements[ 0 ] === "#scrollParent" ) {
                                                        TestHelpers.draggable.setScrollable( "#main", false );
                                                        TestHelpers.draggable.setScrollable( "#scrollParent", true );
                                                }
@@ -867,6 +867,8 @@ test( "scroll, scrollSensitivity, and scrollSpeed", function() {
 test( "#6817: auto scroll goes double distance when dragging", function() {
        expect( 2 );
 
+       TestHelpers.draggable.restoreScroll( document );
+
        var offsetBefore,
                distance = 10,
                viewportHeight = $( window ).height(),
@@ -906,6 +908,7 @@ test( "snap, snapMode, and snapTolerance", function() {
                snapTolerance = 15,
                element = $( "#draggable1" ).draggable({
                        snap: true,
+                       scroll: false,
                        snapMode: "both",
                        snapTolerance: snapTolerance
                }),
@@ -1028,6 +1031,7 @@ test( "#8459: element can snap to an element that was removed during drag", func
                snapTolerance = 15,
                element = $( "#draggable1" ).draggable({
                        snap: true,
+                       scroll: false,
                        snapMode: "both",
                        snapTolerance: snapTolerance,
                        start: function() {
index e789910df990cf2cdf9b85ae64f450a717116a0c..6340c6d6484e63994ca9a33f3dec2f4a41e07729 100644 (file)
@@ -55,18 +55,17 @@ $.fn.extend({
        })( $.fn.focus ),
 
        scrollParent: function() {
-               var scrollParent;
-               if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
-                       scrollParent = this.parents().filter(function() {
-                               return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
-                       }).eq(0);
-               } else {
-                       scrollParent = this.parents().filter(function() {
-                               return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
-                       }).eq(0);
-               }
+               var position = this.css( "position" ),
+                       excludeStaticParent = position === "absolute",
+                       scrollParent = this.parents().filter( function() {
+                               var parent = $( this );
+                               if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
+                                       return false;
+                               }
+                               return (/(auto|scroll)/).test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
+                       }).eq( 0 );
 
-               return ( /fixed/ ).test( this.css( "position") ) || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
+               return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
        },
 
        uniqueId: (function() {
index e528d194ef8dffd5b990b6478f213ba2fb7446d8..f18b383d39dc39289a03b28c58bb962bd465e853 100644 (file)
@@ -334,6 +334,10 @@ $.widget("ui.draggable", $.ui.mouse, {
                }
        },
 
+       _isRootNode: function( element ) {
+               return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
+       },
+
        _getParentOffset: function() {
 
                //Get the offsetParent and cache its position
@@ -349,10 +353,7 @@ $.widget("ui.draggable", $.ui.mouse, {
                        po.top += this.scrollParent.scrollTop();
                }
 
-               //This needs to be actually done for all browsers, since pageX/pageY includes this information
-               //Ugly IE fix
-               if((this.offsetParent[0] === document.body) ||
-                       (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+               if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
                        po = { top: 0, left: 0 };
                }
 
@@ -364,17 +365,18 @@ $.widget("ui.draggable", $.ui.mouse, {
        },
 
        _getRelativeOffset: function() {
-
-               if(this.cssPosition === "relative") {
-                       var p = this.element.position();
-                       return {
-                               top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
-                               left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
-                       };
-               } else {
+               if ( this.cssPosition !== "relative" ) {
                        return { top: 0, left: 0 };
                }
 
+               var p = this.element.position(),
+                       scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
+
+               return {
+                       top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
+                       left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
+               };
+
        },
 
        _cacheMargins: function() {
@@ -458,31 +460,20 @@ $.widget("ui.draggable", $.ui.mouse, {
                }
 
                var mod = d === "absolute" ? 1 : -1,
-                       document = this.document[ 0 ],
-                       useOffsetParent = this.cssPosition === "absolute" && ( this.scrollParent[ 0 ] === document || !$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ),
-                       scroll = useOffsetParent ? this.offsetParent : this.scrollParent,
-                       // we need to test if offsetParent was used here because Blink incorrectly reports a 0 scrollTop
-                       // on document.documentElement when the page is scrolled. Checking for offsetParent normalizes
-                       // this across browsers. Blink bug: https://code.google.com/p/chromium/issues/detail?id=157855
-                       scrollIsRootNode = useOffsetParent && ( /(html|body)/i ).test( scroll[ 0 ].nodeName );
-
-               //Cache the scroll
-               if (!this.offset.scroll) {
-                       this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
-               }
+                       scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
 
                return {
                        top: (
                                pos.top +                                                                                                                               // The absolute mouse position
                                this.offset.relative.top * mod +                                                                                // Only for relative positioned nodes: Relative offset from element to offset parent
                                this.offset.parent.top * mod -                                                                          // The offsetParent's offset without borders (offset + border)
-                               ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
+                               ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
                        ),
                        left: (
                                pos.left +                                                                                                                              // The absolute mouse position
                                this.offset.relative.left * mod +                                                                               // Only for relative positioned nodes: Relative offset from element to offset parent
                                this.offset.parent.left * mod   -                                                                               // The offsetParent's offset without borders (offset + border)
-                               ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : this.offset.scroll.left ) * mod)
+                               ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
                        )
                };
 
@@ -492,19 +483,16 @@ $.widget("ui.draggable", $.ui.mouse, {
 
                var containment, co, top, left,
                        o = this.options,
-                       document = this.document[ 0 ],
-                       useOffsetParent = this.cssPosition === "absolute" && ( this.scrollParent[ 0 ] === document || !$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ),
-                       scroll = useOffsetParent ? this.offsetParent : this.scrollParent,
-                       // we need to test if offsetParent was used here because Blink incorrectly reports a 0 scrollTop
-                       // on document.documentElement when the page is scrolled. Checking for offsetParent normalizes
-                       // this across browsers. Blink bug: https://code.google.com/p/chromium/issues/detail?id=157855
-                       scrollIsRootNode = useOffsetParent && ( /(html|body)/i ).test( scroll[ 0 ].nodeName ),
+                       scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
                        pageX = event.pageX,
                        pageY = event.pageY;
 
-               //Cache the scroll
-               if (!this.offset.scroll) {
-                       this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+               // Cache the scroll
+               if ( !scrollIsRootNode || !this.offset.scroll ) {
+                       this.offset.scroll = {
+                               top: this.scrollParent.scrollTop(),
+                               left: this.scrollParent.scrollLeft()
+                       };
                }
 
                /*
@@ -566,14 +554,14 @@ $.widget("ui.draggable", $.ui.mouse, {
                                this.offset.click.top   -                                                                                               // Click offset (relative to the element)
                                this.offset.relative.top -                                                                                              // Only for relative positioned nodes: Relative offset from element to offset parent
                                this.offset.parent.top +                                                                                                // The offsetParent's offset without borders (offset + border)
-                               ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
+                               ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
                        ),
                        left: (
                                pageX -                                                                                                                                 // The absolute mouse position
                                this.offset.click.left -                                                                                                // Click offset (relative to the element)
                                this.offset.relative.left -                                                                                             // Only for relative positioned nodes: Relative offset from element to offset parent
                                this.offset.parent.left +                                                                                               // The offsetParent's offset without borders (offset + border)
-                               ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
+                               ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
                        )
                };