jQuery(".dropTarget").droppable({ greedy: true, tolerance: 'pointer', hoverClass: 'dropHover', accept: function () { //code left out }, drop: function (event, ui) { //code left out }, over: function (event, ui) { this.folderTimeout = window.setTimeout(function () { var dropObject = jQuery(this); dropObject.find("ul.folderSubList").show(); }, 500); }, out: function () { window.clearTimeout(this.folderTimeout); } });
The over and out events are used to open up the subfolder tree. They use a timeout to make the transition less snappy, more smooth, which works fine. When inspecting the HTML with Firebug (after the code above was run), we could not find anything wrong. The hidden subfolders did get the class "ui-droppable" which droptargets receive when the jQuery ui droppable is initialized. So even though the folders are hidden (by css style "display:none;") they were initialized correctly as droptargets.
I couldn't figure out why, so it was time to pair program. My colleague noticed that it looked like the position of the droptargets were cached when a drag starts. A very sharp observation, because this actually is the case! So what we wanted to was refresh the cached positions once a subfolder tree was opened. The jQuery UI draggable and droppable API does not have a method to force a refresh of the positions. I've found a feature request ticket for the refresh method but it seems the method will probably not be introduced until jQuery UI 2.0 (we're at 1.8.16 at this moment).
Most developers have been at this point: you have to implement certain behaviour into your application, but the plugin you're using does not support that behaviour. At this point you have some options:
- use another plugin which does support it
- find alternative behaviour and ask customer if that's acceptable
- convince the customer it's not possible and abondon it
- dig into the plugin's core and find a workaround or hack to enable the support *
jQuery(".dropTarget").droppable({ greedy: true, tolerance: 'pointer', hoverClass: 'dropHover', accept: function () { //code left out }, drop: function (event, ui) { //code left out }, over: function (event, ui) { this.folderTimeout = window.setTimeout(function () { var dropObject = jQuery(this); dropObject.find("ul.folderSubList").show(); jQuery.ui.ddmanager.prepareOffsets(jQuery.ui.ddmanager.current, null); }, 500); }, out: function () { window.clearTimeout(this.folderTimeout); } });
Trick is to call prepareOffsets on the current jQuery UI drop & dragmanager. Now you'll be able to drop on the dynamically shown elements.
*if the plugin is open source, you can also (or maybe should) try to fix it and do a pull request to get the fix to become a part of the plugin