Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery UI droppable - tolerance/greedy not working as expected

Tags:

jquery-ui

When I drag the draggable, the element containing the droppables keeps getting triggered (because it's also a droppable), even though it's behind the droppables and they're stacked right on each other. It's behaving like there's a gap between the droppables, and there isn't one.

I've made an example on jsFiddle and here's the screenshot of the offending behavior.

If I add padding to .parent (for example padding: 0.2em 0.2em 0em 0.2em the behavior is even worse.

like image 446
DMIL Avatar asked Jun 23 '12 23:06

DMIL


1 Answers

First of all, I hope you found out a solution in these months, I'm answering this because I'm working with jQueryUI in this period and I thought it would be a good exercise to try to find an answer. Also, I hate unanswered questions ^_^

Unfortunately, it really looks like the browser reacts as if between those .child elements there's some space, enough to trigger the *over events for the .parent. The only idea I came up with is to try to detect if, when the dropover events triggers on the parent, the mouse position is actually inside a child element. If so, you should give the accepting_drops class to the child element instead of the parent.

Here's the code (I made a jsFiddle to show my solution in action):

HTML and CSS are unaltered, so I won't copy them again

Javascript

$('.dragme').draggable({
    helper: 'clone' 
});

$('.parent,.child').droppable({
    greedy: true,
    tolerance: 'pointer',
});

$(".parent").on("dropover", function(event, ui) {
    var first = $(".child:first");
    var last = $(".child:last");

    if((event.originalEvent.pageX > first.offset().left) &&
        (event.originalEvent.pageY > first.offset().top) &&
        (event.originalEvent.pageX <= (last.offset().left + last.width())) &&
        (event.originalEvent.pageY <= (last.offset().top + last.height()))) {
        $(this).removeClass("accepting_drops");
    }
    else {
        $(this).addClass("accepting_drops");
        $(".child").removeClass("accepting_drops");
    }
}).on("dropout", function() {
    $(this).removeClass("accepting_drops");
});

$(".child").on("dropover", function() {
    $(".parent").removeClass("accepting_drops");
    $(".child").removeClass("accepting_drops");
    $(this).addClass("accepting_drops");
}).on("dropout", function() {
    $(this).removeClass("accepting_drops");
});

I removed the hoverClass: 'accepting_drops' line because we're overriding the default behaviour of the draggable component. For the parent div, if when a dropover event triggers I'm also inside a child element, I remove the accepting_drops class from it, otherwise I remove it from any child who could have it and add it to the parent instead. When a dropout event triggers on it, I remove the accepting_drops class.

For the child, the behaviour is almost standard, on a dropover event I remove the accepting_drops class from everything else and add it to the child, on a dropout event I remove it.

The behaviour is still a bit of a mistery, but this workaround should do the trick.

like image 195
goffreder Avatar answered Sep 28 '22 08:09

goffreder