9

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.

Ryan Mulready
  • 574
  • 1
  • 5
  • 18

1 Answers1

4

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/

Julien Grégoire
  • 16,045
  • 3
  • 24
  • 51