diff options
-rw-r--r-- | tests/unit/draggable/draggable.html | 8 | ||||
-rw-r--r-- | tests/unit/draggable/draggable_core.js | 37 | ||||
-rw-r--r-- | tests/unit/draggable/draggable_options.js | 8 | ||||
-rw-r--r-- | ui/jquery.ui.core.js | 21 | ||||
-rw-r--r-- | ui/jquery.ui.draggable.js | 64 |
5 files changed, 85 insertions, 53 deletions
diff --git a/tests/unit/draggable/draggable.html b/tests/unit/draggable/draggable.html index dd284f280..42467d2d4 100644 --- a/tests/unit/draggable/draggable.html +++ b/tests/unit/draggable/draggable.html @@ -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> diff --git a/tests/unit/draggable/draggable_core.js b/tests/unit/draggable/draggable_core.js index 1fefb8500..b8ea19930 100644 --- a/tests/unit/draggable/draggable_core.js +++ b/tests/unit/draggable/draggable_core.js @@ -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 ); diff --git a/tests/unit/draggable/draggable_options.js b/tests/unit/draggable/draggable_options.js index ea52eb299..11a3c6840 100644 --- a/tests/unit/draggable/draggable_options.js +++ b/tests/unit/draggable/draggable_options.js @@ -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() { diff --git a/ui/jquery.ui.core.js b/ui/jquery.ui.core.js index e789910df..6340c6d64 100644 --- a/ui/jquery.ui.core.js +++ b/ui/jquery.ui.core.js @@ -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() { diff --git a/ui/jquery.ui.draggable.js b/ui/jquery.ui.draggable.js index e528d194e..f18b383d3 100644 --- a/ui/jquery.ui.draggable.js +++ b/ui/jquery.ui.draggable.js @@ -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 ) ) ) }; |