Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't drag large item to be top/bottom most with jquery-sortable

Have an issue with dragging large items to top-most or bottom-most positions.

Demo: http://jsfiddle.net/vladimir_ze/b2Q9b/17/

Before sorting (on start event) I decrease element size to make sorting large elements easy, but it seems that the calculation still done with element original height (before I set it to smaller size).

Any ideas how to solve that?

Updated

I came across an interesting link (jQuery UI : Before start draggable) recently while searching for if I can change element height before start event, and it turns out it possible to extend sortable with beforeStart event.

var oldMouseStart = $.ui.sortable.prototype._mouseStart;
$.ui.sortable.prototype._mouseStart = function (event, overrideHandle, noActivation) {
    this._trigger('beforeStart', event, this._uiHash());
    oldMouseStart.apply(this, [event, overrideHandle, noActivation]);
};

When beforeStart fires I apply class to minimize the item and also make a call to .sortable('refresh').

Here's the result: http://jsfiddle.net/vladimir_ze/b2Q9b/18/ It still a bit buggy but it works good if you start dragging from the top edge.

like image 947
psycat Avatar asked Jun 02 '15 14:06

psycat


1 Answers

This seems to be a bug in jquery which is already logged.

Fix for it will be available in the version 1.12. Meanwhile you can add the below code to your script as proposed in this link.Working fiddle.

$.widget("ui.sortable", $.extend({}, $.ui.sortable.prototype, {
_mouseDrag: function(event) {
    var i, item, itemElement, intersection,
        o = this.options,
        scrolled = false,
        touchingEdge;

    //Compute the helpers position
    this.position = this._generatePosition(event);
    this.positionAbs = this._convertPositionTo("absolute");

    if (!this.lastPositionAbs) {
        this.lastPositionAbs = this.positionAbs;
    }

    //Do scrolling
    if(this.options.scroll) {
        if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {

            if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
                this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
            } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
                this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
            }

            if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
                this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
            } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
                this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
            }

        } else {

            if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
                scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
            } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
                scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
            }

            if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
                scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
            } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
                scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
            }

        }

        if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
            $.ui.ddmanager.prepareOffsets(this, event);
        }
    }

    //Regenerate the absolute position used for position checks
    this.positionAbs = this._convertPositionTo("absolute");

    //Set the helper position
    if(!this.options.axis || this.options.axis !== "y") {
        this.helper[0].style.left = this.position.left+"px";
    }
    if(!this.options.axis || this.options.axis !== "x") {
        this.helper[0].style.top = this.position.top+"px";
    }

    // 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";
        }
        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";
        }
    }

    if(touchingEdge !== undefined && this.helper[0] !== this.items[touchingEdge].item[0]) {
        // Rearrange, if the helper is touching the edge of the containment and not
        // already the item at the 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;
            }

            // 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;
            }

            // 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;
            }
        }
    }

    //Post events to containers
    this._contactContainers(event);

    //Interconnect with droppables
    if($.ui.ddmanager) {
        $.ui.ddmanager.drag(this, event);
    }

    //Call callbacks
    this._trigger("sort", event, this._uiHash());

    this.lastPositionAbs = this.positionAbs;
    return false;

}
}));
like image 86
John Avatar answered Nov 10 '22 15:11

John