jQuery UI sortable scroll helper element offset Firefox issue

I have a problem with a jQuery UI 1.7.2 sortable list in Firefox 3.6, IE7-8 work fine. When I'm scrolled down a bit, the helper element seems to have an offset of the same height that I'm scrolled down from the mouse pointer which makes it impossible to see which item you originally started dragging. How do I fix this or work around the issue? If there is no fix what is a really good alternative drag-able plugin?

Here are my initialization parameters for the sortable.

$("#sortable").sortable( {placeholder: 'ui-state-highlight'  } );
$("#sortable").disableSelection();

Solution 1:

If you want to prevent browser sniffing, the CSS only solution is to set the ul or a container style to overflow: auto. If you look at the source through firebug, it's the way jQuery does it in their example.

Solution 2:

Using overflow: auto; was not an option for me. I was able to work around this issue with this sort event handler:

$(...).sortable({
    ...
    sort: function(event, ui) {
        var $target = $(event.target);
        if (!/html|body/i.test($target.offsetParent()[0].tagName)) {
            var top = event.pageY - $target.offsetParent().offset().top - (ui.helper.outerHeight(true) / 2);
            ui.helper.css({'top' : top + 'px'});
        }
    },
    ...
});

It is not perfect, but it doesn't require browser sniffing. Tested in IE8, Chrome and Firefox.

Edit: This is using jQuery 1.10.0 and jQuery UI 1.10.3.

Solution 3:

I was seeing this issue and was able to solve it by removing the css rule position:relative from one of the containing divs on my page. See also: http://forum.jquery.com/topic/sortable-offset-when-element-is-dragged-and-page-scrolled-down-ff

Solution 4:

I also had this problem and fixed it with the following code:

var wscrolltop = 0;
$sortable_elements.sortable({ 
    start: function(event, ui) {
        wscrolltop = $(window).scrollTop();
    },
    sort: function(event, ui) {                   
        ui.helper.css({'top' : ui.position.top + wscrolltop + 'px'});
    }
});

I discovered, that there still is a problem if you scroll with your sortable-element. Maybe somebody has a solution for this?

UPDATE: The fix is:

$sortable_elements.sortable({ 
    connectWith: '#personal-favs ul.fitems',
    sort: function(event, ui) {  
        ui.helper.css({'top' : ui.position.top + $(window).scrollTop() + 'px'});
    }
});

But still - if you're leaving the list, the sort-event seems to stop.

Solution 5:

You also need to account for the fact this is specific to firefox, here is the snippet I'm using - I got directed the right way from Harris' solution. I encountered this problem w/o using the helper when the sortable was in a relatively positioned container.

  var options = { 
   handle: '.mover', 
   update:updateSorting 
 };
  var userAgent = navigator.userAgent.toLowerCase();
  if(userAgent.match(/firefox/)) {
    options["start"] = function (event, ui) { ui.item.css('margin-top', $(window).scrollTop() ); };
    options["beforeStop"] = function (event, ui) { ui.item.css('margin-top', 0 ); };
  }
  $("#" + list_id+"").sortable(options);
  $("#" + list_id+"").disableSelection();

You could also do this check on the server and then have 2 different calls depending on the browser.