Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQueryUI Auto Scroll on Drag

http://jsfiddle.net/ujty083a/4/

  $(document).ready(function(){
        $(".left ul li").draggable({
            refreshPosition: true,
            revert: true
        });

        $(".right li").droppable({
            drop:   function(e, ui){
                alert(ui.draggable.text()+" "+$(this).text());
            }
        });

    });

I have three lists one you can drag and the other two accept drop. The right lists may or may not have a scroll bar but there will always be 2 or more.

The first problem I've found is when the top list has a scrollbar and you try to drop an item on the second list two events are triggered. One for the hidden list and one for the visible list.

The second problem is the when one of the lists has a scrollbar it does not auto scroll when the user drags an item into it.

like image 365
Ryan Mulready Avatar asked Oct 23 '15 19:10

Ryan Mulready


Video Answer


1 Answers

I think you'll need to modify droppable and modify substantially some of the behaviors this way:

  • You'll need to add an option to define if the droppable should be scrollable or not.
  • Then you'll need some kind of validation as to which droppable are visible or not.
  • And you'll need to tweak the scroll behavior that are already in some of jquery ui widgets.

This is not perfect but should give you some ideas:

 $.widget('ui.droppable', $.ui.droppable, {

        _over: function (e, ui) {
            var draggable = $.ui.ddmanager.current;
            if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element

            // this to make sure the droppable is visible
            this.scrollVisible = this._isScrollIntoView();

            if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element)) && (!this.options.scrollable || this.scrollVisible)) {

                if (this.options.hoverClass) {
                    this.element.addClass(this.options.hoverClass);
                }
                // to activate scrollable you need to change scrollParent of the draggable
                // and adjust some calculations
                if (this.options.scrollable) {
                    draggable.overflowOffset = $(this.element).scrollParent().offset();
                    draggable.scrollParent = $(this.element).scrollParent();
                    draggable.offsetParent = $(this.element).scrollParent();
                    draggable.offset.parent.top = $(this.element).scrollParent().scrollTop();
                }
                this._trigger('over', event, this.ui(draggable));
            }


        },
        _out: function (event) {

            this._super();
            var draggable = $.ui.ddmanager.current;

            // remove scrollable 
            if (this.options.scrollable) {
                draggable.scrollParent = $(document);
                draggable.offsetParent = $(document);
                draggable.overflowOffset = $(document).offset();
                draggable.offset.parent.top = $(document).scrollTop();
            }
        },
        _drop: function (event, custom) {

            var draggable = custom || $.ui.ddmanager.current;
            if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element

            var childrenIntersection = false;
            this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function () {
                var inst = $.data(this, 'droppable');
                if (
                inst.options.greedy && !inst.options.disabled && inst.options.scope == draggable.options.scope && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && $.ui.intersect(draggable, $.extend(inst, {
                    offset: inst.element.offset()
                }), inst.options.tolerance)) {
                    childrenIntersection = true;
                    return false;
                }
            });
            if (childrenIntersection) return false;

            // same as for over, you need to validate visibility of the element
            this.scrollVisible = this._isScrollIntoView();

            if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element)) && (!this.options.scrollable || this.scrollVisible)) {
                if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
                if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
                this._trigger('drop', event, this.ui(draggable));
                return this.element;
            }

            return false;

        },
        // a function to check visibility. Taken here:
        //http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
        _isScrollIntoView() {

            var $elem = $(this.element);
            var $parent = $(this.element).scrollParent();

            var docViewTop = $parent.parent().scrollTop();
            var docViewBottom = docViewTop + $parent.parent().height();

            var elemTop = $elem.offset().top;
            var elemBottom = elemTop + $elem.height();

            return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
        }
    });



    $(document).ready(function () {
        $(".left ul li").draggable({
            refreshPosition: true,
            revert: true,

        });

        $(".right .top li").droppable({
            scrollable: true,

            drop: function (e, ui) {
                alert(ui.draggable.text() + " " + $(this).text());
            }
        });
        $(".right .bottom li").droppable({
            scrollable: false,

            drop: function (e, ui) {
                alert(ui.draggable.text() + " " + $(this).text());
            }
        });

    });

http://jsfiddle.net/ejv32oen/4/

like image 100
Julien Grégoire Avatar answered Sep 21 '22 22:09

Julien Grégoire