Skip to content

Commit 249bfbb

Browse files
authored
Merge branch 'jquery:main' into master
2 parents 209ae40 + b52ee40 commit 249bfbb

File tree

5 files changed

+246
-64
lines changed

5 files changed

+246
-64
lines changed

tests/unit/sortable/core.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,57 @@ QUnit.test( "ui-sortable-handle applied to appropriate element", function( asser
4242
assert.equal( el.find( ".ui-sortable-handle" ).length, 0, "class name removed on destroy" );
4343
} );
4444

45+
// gh-1998
46+
QUnit.test( "drag & drop works with a zero-height container", function( assert ) {
47+
var ready = assert.async();
48+
assert.expect( 3 );
49+
50+
var el = $( "<ul class='list-gh-1998'>\n" +
51+
" <style>" +
52+
" .list-gh-1998 {\n" +
53+
" margin: 0;\n" +
54+
" padding: 0;\n" +
55+
" }\n" +
56+
" .list-item-gh-1998 {\n" +
57+
" float: left;\n" +
58+
" display: block;\n" +
59+
" width: 100px;\n" +
60+
" height: 100px;\n" +
61+
" }\n" +
62+
" </style>\n" +
63+
" <li class='list-item-gh-1998'>Item 1</li>\n" +
64+
" <li class='list-item-gh-1998'>Item 2</li>\n" +
65+
" <li class='list-item-gh-1998'>Item 3</li>\n" +
66+
"</ul>" )
67+
.sortable()
68+
.appendTo( "#qunit-fixture" );
69+
70+
function step1() {
71+
el.find( "li" ).eq( 0 ).simulate( "drag", {
72+
dx: 100,
73+
dy: 3,
74+
moves: 3
75+
} );
76+
setTimeout( step2 );
77+
}
78+
79+
function step2() {
80+
el.find( "li" ).eq( 2 ).simulate( "drag", {
81+
dx: -200,
82+
dy: -3,
83+
moves: 3
84+
} );
85+
setTimeout( step3 );
86+
}
87+
88+
function step3() {
89+
assert.equal( el.find( "li" ).eq( 0 ).text(), "Item 3" );
90+
assert.equal( el.find( "li" ).eq( 1 ).text(), "Item 2" );
91+
assert.equal( el.find( "li" ).eq( 2 ).text(), "Item 1" );
92+
ready();
93+
}
94+
95+
step1();
96+
} );
97+
4598
} );

tests/unit/sortable/options.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,63 @@ QUnit.test( "{ placholder: String } tbody", function( assert ) {
488488
} );
489489
} );
490490

491+
// gh-2001
492+
// Sortable: Draggable items moved into a sortable had incorrect position
493+
QUnit.test( "{ connectToSortable: Selector } positioning (gh-2001)", function( assert ) {
494+
assert.expect( 1 );
495+
496+
// Code from jQuery Simulate with minor modifications.
497+
function findCenter( elem ) {
498+
var offset,
499+
document = $( elem[ 0 ].ownerDocument );
500+
offset = elem.offset();
501+
502+
return {
503+
x: Math.floor( offset.left + elem.outerWidth() / 2 - document.scrollLeft() ),
504+
y: Math.floor( offset.top + elem.outerHeight() / 2 - document.scrollTop( ) )
505+
};
506+
}
507+
508+
var sortableElem = $( "#sortable" );
509+
510+
sortableElem.css( "position", "relative" );
511+
512+
var item = $( "<div></div>" )
513+
.text( "6" )
514+
.insertBefore( "#sortable" );
515+
516+
// Padding
517+
$( "<div></div>" )
518+
.css( {
519+
width: "100px",
520+
height: "100px"
521+
} )
522+
.insertBefore( "#sortable" );
523+
524+
item.draggable( {
525+
connectToSortable: "#sortable"
526+
} );
527+
sortableElem.sortable();
528+
529+
// Simulate a drag without a drop.
530+
var center = findCenter( item );
531+
item.simulate( "mousedown", {
532+
clientX: center.x,
533+
clientY: center.y
534+
} );
535+
item.simulate( "mousemove", {
536+
clientX: center.x,
537+
clientY: center.y + 60
538+
} );
539+
item.simulate( "mousemove", {
540+
clientX: center.x,
541+
clientY: center.y + 120
542+
} );
543+
544+
assert.ok( item.offset().top > sortableElem.children().eq( 0 ).offset().top,
545+
"Draggable offset correct after moving into a sortable" );
546+
} );
547+
491548
/*
492549
Test("{ revert: false }, default", function() {
493550
ok(false, "missing test - untested code is broken code.");

tests/unit/tooltip/core.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,74 @@ QUnit.test( "remove conflicting attributes from live region", function( assert )
254254
.tooltip( "open" );
255255
} );
256256

257+
// gh-1990
258+
QUnit.test( "don't crash on empty tooltip content", function( assert ) {
259+
var ready = assert.async();
260+
assert.expect( 1 );
261+
262+
var anchor = $( "#tooltipped1" ),
263+
input = anchor.next(),
264+
actions = [];
265+
266+
$( document ).tooltip( {
267+
show: false,
268+
hide: false,
269+
content: function() {
270+
var title = $( this ).attr( "title" );
271+
if ( title === "inputtitle" ) {
272+
return "";
273+
}
274+
return title;
275+
},
276+
open: function( event, ui ) {
277+
actions.push( "open:" + ui.tooltip.text() );
278+
},
279+
close: function( event, ui ) {
280+
actions.push( "close:" + ui.tooltip.text() );
281+
}
282+
} );
283+
284+
function step1() {
285+
anchor.simulate( "mouseover" );
286+
setTimeout( step2 );
287+
}
288+
289+
function step2() {
290+
anchor.simulate( "mouseout" );
291+
setTimeout( step3 );
292+
}
293+
294+
function step3() {
295+
input.simulate( "focus" );
296+
setTimeout( step4 );
297+
}
298+
299+
function step4() {
300+
input.simulate( "blur" );
301+
setTimeout( step5 );
302+
}
303+
304+
function step5() {
305+
anchor.simulate( "mouseover" );
306+
setTimeout( step6 );
307+
}
308+
309+
function step6() {
310+
anchor.simulate( "mouseout" );
311+
setTimeout( step7 );
312+
}
313+
314+
function step7() {
315+
assert.deepEqual( actions, [
316+
"open:anchortitle",
317+
"close:anchortitle",
318+
"open:anchortitle",
319+
"close:anchortitle"
320+
], "Tooltip opens and closes without crashing" );
321+
ready();
322+
}
323+
324+
step1();
325+
} );
326+
257327
} );

ui/widgets/sortable.js

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -421,79 +421,76 @@ return $.widget( "ui.sortable", $.ui.mouse, {
421421
this.helper[ 0 ].style.top = this.position.top + "px";
422422
}
423423

424-
//Post events to containers
425-
this._contactContainers( event );
426-
427-
if ( this.innermostContainer !== null ) {
428-
429-
//Do scrolling
430-
if ( o.scroll ) {
431-
if ( this._scroll( event ) !== false ) {
424+
//Do scrolling
425+
if ( o.scroll ) {
426+
if ( this._scroll( event ) !== false ) {
432427

433-
//Update item positions used in position checks
434-
this._refreshItemPositions( true );
428+
//Update item positions used in position checks
429+
this._refreshItemPositions( true );
435430

436-
if ( $.ui.ddmanager && !o.dropBehaviour ) {
437-
$.ui.ddmanager.prepareOffsets( this, event );
438-
}
431+
if ( $.ui.ddmanager && !o.dropBehaviour ) {
432+
$.ui.ddmanager.prepareOffsets( this, event );
439433
}
440434
}
435+
}
441436

442-
this.dragDirection = {
443-
vertical: this._getDragVerticalDirection(),
444-
horizontal: this._getDragHorizontalDirection()
445-
};
446-
447-
//Rearrange
448-
for ( i = this.items.length - 1; i >= 0; i-- ) {
449-
450-
//Cache variables and intersection, continue if no intersection
451-
item = this.items[ i ];
452-
itemElement = item.item[ 0 ];
453-
intersection = this._intersectsWithPointer( item );
454-
if ( !intersection ) {
455-
continue;
456-
}
457-
458-
// Only put the placeholder inside the current Container, skip all
459-
// items from other containers. This works because when moving
460-
// an item from one container to another the
461-
// currentContainer is switched before the placeholder is moved.
462-
//
463-
// Without this, moving items in "sub-sortables" can cause
464-
// the placeholder to jitter between the outer and inner container.
465-
if ( item.instance !== this.currentContainer ) {
466-
continue;
467-
}
437+
this.dragDirection = {
438+
vertical: this._getDragVerticalDirection(),
439+
horizontal: this._getDragHorizontalDirection()
440+
};
468441

469-
// Cannot intersect with itself
470-
// no useless actions that have been done before
471-
// no action if the item moved is the parent of the item checked
472-
if ( itemElement !== this.currentItem[ 0 ] &&
473-
this.placeholder[ intersection === 1 ?
474-
"next" : "prev" ]()[ 0 ] !== itemElement &&
475-
!$.contains( this.placeholder[ 0 ], itemElement ) &&
476-
( this.options.type === "semi-dynamic" ?
477-
!$.contains( this.element[ 0 ], itemElement ) :
478-
true
479-
)
480-
) {
442+
//Rearrange
443+
for ( i = this.items.length - 1; i >= 0; i-- ) {
481444

482-
this.direction = intersection === 1 ? "down" : "up";
445+
//Cache variables and intersection, continue if no intersection
446+
item = this.items[ i ];
447+
itemElement = item.item[ 0 ];
448+
intersection = this._intersectsWithPointer( item );
449+
if ( !intersection ) {
450+
continue;
451+
}
483452

484-
if ( this.options.tolerance === "pointer" ||
485-
this._intersectsWithSides( item ) ) {
486-
this._rearrange( event, item );
487-
} else {
488-
break;
489-
}
453+
// Only put the placeholder inside the current Container, skip all
454+
// items from other containers. This works because when moving
455+
// an item from one container to another the
456+
// currentContainer is switched before the placeholder is moved.
457+
//
458+
// Without this, moving items in "sub-sortables" can cause
459+
// the placeholder to jitter between the outer and inner container.
460+
if ( item.instance !== this.currentContainer ) {
461+
continue;
462+
}
490463

491-
this._trigger( "change", event, this._uiHash() );
464+
// Cannot intersect with itself
465+
// no useless actions that have been done before
466+
// no action if the item moved is the parent of the item checked
467+
if ( itemElement !== this.currentItem[ 0 ] &&
468+
this.placeholder[ intersection === 1 ?
469+
"next" : "prev" ]()[ 0 ] !== itemElement &&
470+
!$.contains( this.placeholder[ 0 ], itemElement ) &&
471+
( this.options.type === "semi-dynamic" ?
472+
!$.contains( this.element[ 0 ], itemElement ) :
473+
true
474+
)
475+
) {
476+
477+
this.direction = intersection === 1 ? "down" : "up";
478+
479+
if ( this.options.tolerance === "pointer" ||
480+
this._intersectsWithSides( item ) ) {
481+
this._rearrange( event, item );
482+
} else {
492483
break;
493484
}
485+
486+
this._trigger( "change", event, this._uiHash() );
487+
break;
494488
}
495489
}
496490

491+
//Post events to containers
492+
this._contactContainers( event );
493+
497494
//Interconnect with droppables
498495
if ( $.ui.ddmanager ) {
499496
$.ui.ddmanager.drag( this, event );
@@ -888,10 +885,14 @@ return $.widget( "ui.sortable", $.ui.mouse, {
888885
this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
889886
false;
890887

891-
if ( this.innermostContainer !== null ) {
892-
this._refreshItemPositions( fast );
888+
// This has to be redone because due to the item being moved out/into the offsetParent,
889+
// the offsetParent's position will change
890+
if ( this.offsetParent && this.helper ) {
891+
this.offset.parent = this._getParentOffset();
893892
}
894893

894+
this._refreshItemPositions( fast );
895+
895896
var i, p;
896897

897898
if ( this.options.custom && this.options.custom.refreshContainers ) {
@@ -1038,8 +1039,6 @@ return $.widget( "ui.sortable", $.ui.mouse, {
10381039

10391040
}
10401041

1041-
this.innermostContainer = innermostContainer;
1042-
10431042
// If no intersecting containers found, return
10441043
if ( !innermostContainer ) {
10451044
return;

ui/widgets/tooltip.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,10 @@ $.widget( "ui.tooltip", {
352352
// tooltips will handle this in destroy.
353353
if ( target[ 0 ] !== this.element[ 0 ] ) {
354354
events.remove = function() {
355-
this._removeTooltip( this._find( target ).tooltip );
355+
var targetElement = this._find( target );
356+
if ( targetElement ) {
357+
this._removeTooltip( targetElement.tooltip );
358+
}
356359
};
357360
}
358361

0 commit comments

Comments
 (0)