Skip to content

Commit 95546c5

Browse files
committed
Draggable: No cloning in connectToSortable and ensure correct position
Draggables now forcefully recalculate their position when dragged out of a sortable. Sortables now override draggable position when a draggable is dragged into it. Lastly, no longer remove sortable helper when dragging a draggable out, which allows us to not use a clone. Fixes #7734 Fixes #8809 Closes jquerygh-1322
1 parent a62612c commit 95546c5

File tree

3 files changed

+139
-29
lines changed

3 files changed

+139
-29
lines changed

tests/unit/draggable/draggable.html

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@
4646
#draggable3, #draggable4 {
4747
z-index: 100;
4848
}
49+
#sortable {
50+
position: relative;
51+
top: 8000px;
52+
left: 10px;
53+
}
54+
#sortable2 {
55+
position: relative;
56+
top: 9000px;
57+
left: 10px;
58+
}
59+
.sortable {
60+
width: 300px;
61+
height: 100px;
62+
padding: 0;
63+
margin: 0;
64+
border: 0;
65+
}
66+
.sortable li {
67+
height: 100px;
68+
padding: 0;
69+
margin: 0;
70+
border: 0;
71+
list-style: none;
72+
display: inline-block;
73+
}
4974
</style>
5075

5176
<script src="../../../external/qunit/qunit.js"></script>
@@ -60,7 +85,8 @@
6085
"ui/mouse.js",
6186
"ui/resizable.js",
6287
"ui/draggable.js",
63-
"ui/droppable.js"
88+
"ui/droppable.js",
89+
"ui/sortable.js"
6490
]
6591
});
6692
</script>
@@ -90,6 +116,18 @@
90116
</div>
91117
<div style="width: 1px; height: 1000px;"></div>
92118
<div style="position: absolute; width: 1px; height: 2000px;"></div>
119+
<ul id="sortable" class="sortable">
120+
<li>Item 0</li>
121+
<li id="draggableSortable">Item 1</li>
122+
<li>Item 2</li>
123+
<li>Item 3</li>
124+
</ul>
125+
<ul id="sortable2" class="sortable">
126+
<li id="draggableSortableClone">Item 0</li>
127+
<li>Item 1</li>
128+
<li>Item 2</li>
129+
<li>Item 3</li>
130+
</ul>
93131
</div>
94132

95133
</body>

tests/unit/draggable/draggable_options.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,72 @@ test( "{ connectToSortable: selector }, default", function() {
252252
});
253253
*/
254254

255+
test( "connectToSortable, dragging out of a sortable", function() {
256+
expect( 3 );
257+
258+
var sortItem, dragHelper,
259+
element = $( "#draggableSortable" ).draggable({
260+
scroll: false,
261+
connectToSortable: "#sortable"
262+
}),
263+
sortable = $( "#sortable" ).sortable(),
264+
dx = 50,
265+
dy = 50,
266+
offsetBefore = element.offset(),
267+
offsetExpected = {
268+
left: offsetBefore.left + dx,
269+
top: offsetBefore.top + dy
270+
};
271+
272+
$( sortable ).one( "sortstart", function( event, ui ) {
273+
sortItem = ui.item;
274+
});
275+
276+
$( element ).one( "drag", function( event, ui ) {
277+
dragHelper = ui.helper;
278+
});
279+
280+
$( element ).one( "dragstop", function( event, ui ) {
281+
// http://bugs.jqueryui.com/ticket/8809
282+
// Position issue when connected to sortable
283+
deepEqual( ui.helper.offset(), offsetExpected, "draggable offset is correct" );
284+
285+
// http://bugs.jqueryui.com/ticket/7734
286+
// HTML IDs are removed when dragging to a Sortable
287+
equal( sortItem[ 0 ], dragHelper[ 0 ], "both have the same helper" );
288+
equal( sortItem.attr( "id" ), dragHelper.attr( "id" ), "both have the same id" );
289+
});
290+
291+
element.simulate( "drag", {
292+
dx: dx,
293+
dy: dy
294+
});
295+
});
296+
297+
test( "connectToSortable, dragging clone into sortable", function() {
298+
expect( 1 );
299+
300+
var element = $( "#draggableSortableClone" ).draggable({
301+
scroll: false,
302+
connectToSortable: "#sortable",
303+
helper: "clone"
304+
}),
305+
sortable = $( "#sortable" ).sortable(),
306+
offsetSortable = sortable.offset();
307+
308+
$( sortable ).one( "sortbeforestop", function( event, ui ) {
309+
// http://bugs.jqueryui.com/ticket/8809
310+
// Position issue when connected to sortable
311+
deepEqual( ui.helper.offset(), offsetSortable, "sortable offset is correct" );
312+
});
313+
314+
element.simulate( "drag", {
315+
x: offsetSortable.left + 1,
316+
y: offsetSortable.top + 1,
317+
moves: 1
318+
});
319+
});
320+
255321
test( "{ containment: Element }", function() {
256322
expect( 1 );
257323

ui/draggable.js

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -177,23 +177,8 @@ $.widget("ui.draggable", $.ui.mouse, {
177177
this.offsetParentCssPosition = this.offsetParent.css( "position" );
178178

179179
//The element's absolute position on the page minus margins
180-
this.offset = this.positionAbs = this.element.offset();
181-
this.offset = {
182-
top: this.offset.top - this.margins.top,
183-
left: this.offset.left - this.margins.left
184-
};
185-
186-
//Reset scroll cache
187-
this.offset.scroll = false;
188-
189-
$.extend(this.offset, {
190-
click: { //Where the click happened, relative to the element
191-
left: event.pageX - this.offset.left,
192-
top: event.pageY - this.offset.top
193-
},
194-
parent: this._getParentOffset(),
195-
relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
196-
});
180+
this.positionAbs = this.element.offset();
181+
this._refreshOffsets( event );
197182

198183
//Generate the original position
199184
this.originalPosition = this.position = this._generatePosition( event, false );
@@ -234,6 +219,21 @@ $.widget("ui.draggable", $.ui.mouse, {
234219
return true;
235220
},
236221

222+
_refreshOffsets: function( event ) {
223+
this.offset = {
224+
top: this.positionAbs.top - this.margins.top,
225+
left: this.positionAbs.left - this.margins.left,
226+
scroll: false,
227+
parent: this._getParentOffset(),
228+
relative: this._getRelativeOffset()
229+
};
230+
231+
this.offset.click = {
232+
left: event.pageX - this.offset.left,
233+
top: event.pageY - this.offset.top
234+
};
235+
},
236+
237237
_mouseDrag: function(event, noPropagation) {
238238
// reset any necessary cached properties (see #5009)
239239
if ( this.offsetParentCssPosition === "fixed" ) {
@@ -736,11 +736,13 @@ $.ui.plugin.add("draggable", "connectToSortable", {
736736

737737
this.instance.options.helper = this.instance.options._helper;
738738

739-
//If the helper has been the original item, restore properties in the sortable
740-
if (inst.options.helper === "original") {
741-
this.instance.currentItem.css({ top: "auto", left: "auto" });
742-
}
743-
739+
// restore properties in the sortable, since the draggable may have
740+
// modified them in unexpected ways (#8809)
741+
this.instance.currentItem.css({
742+
position: this.instance.placeholder.css( "position" ),
743+
top: "",
744+
left: ""
745+
});
744746
} else {
745747
this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
746748
this.instance._trigger("deactivate", event, uiSortable);
@@ -750,8 +752,6 @@ $.ui.plugin.add("draggable", "connectToSortable", {
750752

751753
},
752754
drag: function( event, ui, draggable ) {
753-
var dragElement = this;
754-
755755
$.each( draggable.sortables, function() {
756756
var innermostIntersecting = false,
757757
thisSortable = this,
@@ -787,9 +787,7 @@ $.ui.plugin.add("draggable", "connectToSortable", {
787787

788788
sortable.isOver = 1;
789789

790-
sortable.currentItem = $( dragElement )
791-
.clone()
792-
.removeAttr( "id" )
790+
sortable.currentItem = ui.helper
793791
.appendTo( sortable.element )
794792
.data( "ui-sortable-item", true );
795793

@@ -827,6 +825,10 @@ $.ui.plugin.add("draggable", "connectToSortable", {
827825

828826
if ( sortable.currentItem ) {
829827
sortable._mouseDrag( event );
828+
// Copy the sortable's position because the draggable's can potentially reflect
829+
// a relative position, while sortable is always absolute, which the dragged
830+
// element has now become. (#8809)
831+
ui.position = sortable.position;
830832
}
831833

832834
} else {
@@ -846,11 +848,15 @@ $.ui.plugin.add("draggable", "connectToSortable", {
846848
sortable._mouseStop( event, true );
847849
sortable.options.helper = sortable.options._helper;
848850

849-
sortable.currentItem.remove();
850851
if ( sortable.placeholder ) {
851852
sortable.placeholder.remove();
852853
}
853854

855+
// Recalculate the draggable's offset considering the sortable
856+
// may have modified them in unexpected ways (#8809)
857+
draggable._refreshOffsets( event );
858+
ui.position = draggable._generatePosition( event, true );
859+
854860
draggable._trigger( "fromSortable", event );
855861

856862
// draggable revert needs that

0 commit comments

Comments
 (0)