diff --git a/tests/unit/sortable/sortable.html b/tests/unit/sortable/sortable.html index 8e0bac501f4..891918a7614 100644 --- a/tests/unit/sortable/sortable.html +++ b/tests/unit/sortable/sortable.html @@ -44,6 +44,29 @@ border-width: 0; height:19px; } + #sortable-horizontal { + width: 142px; + height: 22px; + } + #sortable-vertical { + width: 22px; + height: 142px; + } + #sortable-grid { + width: 62px; + height: 62px; + } + .sortable-axis span { + display: inline-block; + width: 20px; + height: 20px; + } + .sortable-axis span.wide { + width: 60px; + } + .sortable-axis span.tall { + height: 60px; + } #sortable-table { width: 100%; } @@ -66,6 +89,34 @@

  • Item 5
  • +
    + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 +
    + +
    + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 +
    + +
    + Item 1 + Item 2 + Item 3 + Item 4 + Item 5 + Item 6 + Item 7 + Item 8 + Item 9 +
    + diff --git a/tests/unit/sortable/sortable_options.js b/tests/unit/sortable/sortable_options.js index f2beb4dbcd6..cec159a14cb 100644 --- a/tests/unit/sortable/sortable_options.js +++ b/tests/unit/sortable/sortable_options.js @@ -212,9 +212,127 @@ test("{ containment: 'window' }", function() { test("{ containment: Selector }", function() { ok(false, "missing test - untested code is broken code."); +});*/ + +test("#5772: wide element intersect sorting to first and last position on x-axis", function() { + expect(2); + + var element = $("#sortable-horizontal").sortable({ + axis: "x", + containment: "parent", + scroll: false, + tolerance: "intersect" + }), + item = element.find(".wide").eq(0); + + item.simulate("drag", { dx: -150 }); + + equal(item.index(), 0, "Item is sorted to first position"); + + item.simulate("drag", { dx: 150 }); + + equal(item.index(), 4, "Item is sorted to last position"); +}); + +test("#5772: wide element pointer sorting to first and last position on x-axis", function() { + expect(2); + + var element = $("#sortable-horizontal").sortable({ + axis: "x", + containment: "parent", + scroll: false, + tolerance: "pointer" + }), + item = element.find(".wide").eq(0); + + item.simulate("drag", { dx: -150 }); + + equal(item.index(), 0, "Item is sorted to first position"); + + item.simulate("drag", { dx: 150 }); + + equal(item.index(), 4, "Item is sorted to last position"); +}); + +test("#5772: tall element intersect sorting to first and last position on y-axis", function() { + expect(2); + + var element = $("#sortable-vertical").sortable({ + axis: "y", + containment: "parent", + scroll: false, + tolerance: "intersect" + }), + item = element.find(".tall").eq(0); + + item.simulate("drag", { dy: -150 }); + + equal(item.index(), 0, "Item is sorted to first position"); + + item.simulate("drag", { dy: 150 }); + + equal(item.index(), 4, "Item is sorted to last position"); +}); + +test("#5772: tall element pointer sorting to first and last position on y-axis", function() { + expect(2); + + var element = $("#sortable-vertical").sortable({ + axis: "y", + containment: "parent", + scroll: false, + tolerance: "pointer" + }), + item = element.find(".tall").eq(0); + + item.simulate("drag", { dy: -150 }); + + equal(item.index(), 0, "Item is sorted to first position"); + + item.simulate("drag", { dy: 150 }); + + equal(item.index(), 4, "Item is sorted to last position"); +}); + +test("#5772: element intersect sorting to first and last position on grid", function() { + expect(2); + + var element = $("#sortable-grid").sortable({ + containment: "parent", + scroll: false, + tolerance: "intersect" + }), + item = element.find("span").eq(5); + + item.simulate("drag", { dy: -150, dx: -150 }); + + equal(item.index(), 0, "Item is sorted to first position"); + + item.simulate("drag", { dx: 150, dy: 150 }); + + equal(item.index(), 8, "Item is sorted to last position"); +}); + +test("#5772: element pointer sorting to first and last position on grid", function() { + expect(2); + + var element = $("#sortable-grid").sortable({ + containment: "parent", + scroll: false, + tolerance: "pointer" + }), + item = element.find("span").eq(5); + + item.simulate("drag", { dy: -150, dx: -150 }); + + equal(item.index(), 0, "Item is sorted to first position"); + + item.simulate("drag", { dx: 150, dy: 150 }); + + equal(item.index(), 8, "Item is sorted to last position"); }); -test("{ cursor: 'auto' }, default", function() { +/*test("{ cursor: 'auto' }, default", function() { ok(false, "missing test - untested code is broken code."); }); diff --git a/ui/jquery.ui.sortable.js b/ui/jquery.ui.sortable.js index c76a023977a..0643eb19c3c 100644 --- a/ui/jquery.ui.sortable.js +++ b/ui/jquery.ui.sortable.js @@ -284,7 +284,8 @@ $.widget("ui.sortable", $.ui.mouse, { _mouseDrag: function(event) { var i, item, itemElement, intersection, o = this.options, - scrolled = false; + scrolled = false, + touchingEdge; //Compute the helpers position this.position = this._generatePosition(event); @@ -342,47 +343,66 @@ $.widget("ui.sortable", $.ui.mouse, { this.helper[0].style.top = this.position.top+"px"; } - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; + // Check if the helper is touching the edges of the containment. + if(this.containment) { + if((this.positionAbs.left === this.containment[0] || this.options.axis === "y") && + (this.positionAbs.top === this.containment[1] || this.options.axis === "x")) { + touchingEdge = 0; + this.direction = "down"; } - - // Only put the placeholder inside the current Container, skip all - // items from other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this, moving items in "sub-sortables" can cause - // the placeholder to jitter beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; + else if((this.positionAbs.left === this.containment[2] || this.options.axis === "y") && + (this.positionAbs.top === this.containment[3] || this.options.axis === "x")) { + touchingEdge = this.items.length - 1; + this.direction = "up"; } + } - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { + if(touchingEdge !== undefined && this.placeholder[0] !== this.items[touchingEdge].item[0]) { + // Rearrange if the helper is at the edge of the containment and the placeholder is not at that edge. + this._rearrange(event, this.items[touchingEdge], false); + this._trigger("change", event, this._uiHash()); + } else { + //Rearrange + for (i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } - this.direction = intersection === 1 ? "down" : "up"; + // Only put the placeholder inside the current Container, skip all + // items from other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this, moving items in "sub-sortables" can cause + // the placeholder to jitter beetween the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) + ) { + this.direction = intersection === 1 ? "down" : "up"; + + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); break; } - - this._trigger("change", event, this._uiHash()); - break; } }