DRAGGABLE + SCROLLED CONTAINER

http://stackoverflow.com/questions/13808560/scroll-multiple-drop-containers-with-jquery-ui-draggable-droppable

by bizamajig

HTML

<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<p>How can I force the red and green drop targets to scroll when the blue box is dragged over them?</p>
<div class="draggable">drag me</div>
<div class="stage"></div>
<div class="stage"></div>
<div id="debug"></div>

CSS

.draggable {
    background-color: cornflowerblue;
    width: 50px;
    height: 50px;
    z-index: 99999999;
}
.stage {
    background-color: red;
    height: 90px;
    overflow: auto;
    width: 150px;
    display: inline-block;
}
.droptarget {
    height: 20px;
    background-color: green;
    border: 1px solid black;
    margin-bottom: 5px;
}
.droptarget.hovered {
    background-color: yellow;
}
p, .draggable, .stage {
    margin-bottom: 10px;
}

JavaScript

$(".stage").each(function() {
    var $this = $(this);
    for (var i = 0; i < 100; i += 1) {
        $this.append(
            $("<div class='droptarget'></div>")
                .text("drop target " + i)
                .droppable({ hoverClass: "hovered" })
        );
    }
});

var triggerZone = 20;
var scrollSpeed = 2;
$(".draggable").draggable({
    drag: function(event, ui){
        $(".stage").each(function(){
            var $this = $(this);
            var cOffset = $this.offset();
            var bottomPos = cOffset.top + $this.height();
            clearInterval($this.data('timerScroll'));
            $this.data('timerScroll', false);
            if(event.pageX >= cOffset.left && event.pageX <= cOffset.left + $this.width())
            {
                if(event.pageY >= bottomPos - triggerZone && event.pageY <= bottomPos)
                {
                    var moveUp = function() {
                        $this.scrollTop($this.scrollTop() + scrollSpeed);
                    };
                    $this.data('timerScroll', setInterval(moveUp, 10));
                    moveUp();
                }
                if(event.pageY >= cOffset.top && event.pageY <= cOffset.top + triggerZone)
                {
                    var moveDown = function() {
                        $this.scrollTop($this.scrollTop() - scrollSpeed);
                    };
                    $this.data('timerScroll', setInterval(moveDown, 10));
                    moveDown();
                }
            }
        });
    },
    stop: function() {
        $(".stage").each(function(){
            clearInterval($(this).data('timerScroll'));
            $(this).data('timerScroll', false);
        });
    },
    refreshPositions: true /* So as it detect the correct sub-element  */
});