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
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.
sort: function(e, ui){
var tempVariable = $(ui.item.get(0));
tempVariable.css('top', (e.clientY)-(tempVariable.css("height").replace("px", "")));
}
I force scrollbars on my site so this scrollable offset problem occurs due to having html { overflow-y: scroll }
in my CSS.
As I turn scrollable on and off, I used the following to get around it. I've only tested it in IE8, FF12 and Chrome...
turnSortingOnOff:function(e) {
e.preventDefault();
if (stopOrdering()) {
// get rid of the hacky css on the html element
$('html').css({ 'overflow-y': '' });
$('html').css({ 'margin-right': '' });
elmt.sortable('disable');
}
else if (startOrdering()) {
// if the body is smaller than the window
// then there aren't any scrollbars
// in which case, add a right hand margin of 16px
// to the html to prevent the site wobbling
if ($('body').outerHeight() <= $(window).height()) {
$('html').css({ 'margin-right': 16 });
}
// then override the { overflow-y: scroll }
// in the css by setting it to a nice, safe inherit
$('html').css({ 'overflow-y': 'inherit' });
elmt.sortable('enable');
}
}
Obviously it's not bulletproof - if the document size changes while sorting then other things will have to be done. However, in my experience it looks less weird under those circumstances.
To summarize your efforts and provide a completed solution. The following seemed to work for Chrome 40+ and Firefox 30+
var isFirefox = /firefox/.test(navigator.userAgent.toLowerCase());
$('#target').sortable({
connectWith: '#target-holder .elements',
handle: ".element-header",
start: function(ev, ui) {
if( isFirefox ) {
ui.item.css('margin-top', $(window).scrollTop() );
}
},
sort: function(ev, ui) {
if( isFirefox) {
ui.helper.css({'top' : ui.position.top - $(window).scrollTop() + 'px'});
} else {
ui.helper.css({'top' : ui.position.top + $(window).scrollTop() + 'px'});
}
},
beforeStop: function (ev, ui) {
if( isFirefox ) {
ui.item.css('margin-top', 0 );
}
}
});
Had the same problem. In my case it wasnt possible to use the "overflow:auto"-fix. So this is what I did.
var pos_fixed = 1; // switch variable (the fix should only be fired ones)
$('.drag').draggable({
start: function(event, ui){
pos_fixed = 0; // we're about to start, set to not fixed yet
},
drag: function(event, ui){
if(pos_fixed == 0){ // check if the fix hasn't been fired for this instance yet
var help_pos = $(ui.helper).offset().top, // get helpers offset
targ_pos = $(event.target).offset().top, // get targets(the dragged elements) offset
marg = targ_pos-help_pos; // calculate the margin the helper has to have to put it on the same y-position as our target
$(ui.helper).css('margin-top', marg); // put our helper on the same y-position as the target
pos_fixed = 1; // we've fixed it, we don't want it to fire again
}
}
});
The fix doesn't care about what browser you are using. It will always make sure that the helper has the same y-offset as the target when the drag starts.
I managed to figure out a fix for this:
$( "items" ).sortable({
start: function (event, ui) {
if( ui.helper !== undefined )
ui.helper.css('position','absolute').css('margin-top', $(window).scrollTop() );
},
beforeStop: function (event, ui) {
if( ui.offset !== undefined )
ui.helper.css('margin-top', 0);
},
placeholder: 'placeholder-class'
});
Basically, you need to listen for the sortable's "start" event to add the browser's current scrollTop() value to the helper's position, and then you need to listen for the sortable's "beforeStop" event, to remove that offset before the item is officially placed back into the list at its new position.
Hope that's helpful to someone!