web-dev-qa-db-fra.com

jQuery UI, élément d'assistance de défilement triable, problème lié à Firefox

J'ai un problème avec une liste triable jQuery UI 1.7.2 dans Firefox 3.6, IE7-8 fonctionne bien. Lorsque je fais défiler un peu vers le bas, l'élément d'assistance semble avoir un décalage de la même hauteur que celle que je fais défiler du pointeur de la souris, ce qui rend impossible de voir quel élément vous avez commencé à faire glisser à l'origine ..__ Comment puis-je résoudre ce problème ou contourner le problème? S'il n'y a pas de solution, quelle est la meilleure alternative au plugin drag-capable?

Voici mes paramètres d'initialisation pour le triable.

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

Je voyais ce problème et je pouvais le résoudre en supprimant la position de la règle css: relative de l’un des div contenant de ma page. Voir aussi: http://forum.jquery.com/topic/sortable-offset-when-element-is-dragged-and-page-scrolled-down-ff

23
craig

Si vous souhaitez empêcher l’information sur le navigateur, la seule solution CSS est de définir le style ul ou un conteneur sur overflow: auto. Si vous regardez la source via firebug, c'est la façon dont jQuery le fait dans leur exemple .

126
munch

Utiliser overflow: auto; n'était pas une option pour moi. J'ai pu contourner ce problème avec ce gestionnaire d'événements sort:

$(...).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'});
        }
    },
    ...
});

Ce n'est pas parfait, mais il ne nécessite pas de recherche de navigateur. Testé dans IE8, Chrome et Firefox.

Edit : Ceci utilise jQuery 1.10.0 et jQuery UI 1.10.3.

40
rtcherry

J'ai aussi eu ce problème et l'ai corrigé avec le code suivant: 

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'});
    }
});

J'ai découvert qu'il y avait toujours un problème si vous faites défiler avec votre élément triable. Peut-être que quelqu'un a une solution pour cela?

UPDATE: Le correctif est:

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

Mais quand même - si vous quittez la liste, l'événement de tri semble s'arrêter.

20
Theodor

Vous devez également tenir compte du fait que ceci est spécifique à firefox. Voici l'extrait de code que j'utilise - la solution de Harris m'a orientée dans le bon sens. J'ai rencontré ce problème sans utiliser l'aide lorsque le triable était dans un conteneur relativement positionné.

  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();

Vous pouvez également effectuer cette vérification sur le serveur, puis avoir 2 appels différents selon le navigateur.

9
Russell

J'ai réussi à trouver un correctif pour ceci:

$( "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'
});

Fondamentalement, vous devez écouter l'événement "start" du triable pour ajouter la valeur scrollTop () actuelle du navigateur à la position de l'aide, puis vous devez écouter l'événement "beforeStop" du triable, pour supprimer ce décalage avant que l'élément soit officiellement replacé dans la liste à sa nouvelle position.

J'espère que c'est utile pour quelqu'un!

7
Jonathan Harris

Je force les barres de défilement sur mon site afin que ce problème de décalage de défilement se produise en raison d'avoir html { overflow-y: scroll } dans mon CSS.

En activant et désactivant le défilement, j’utilisais ce qui suit pour le contourner. Je ne l'ai testé que dans IE8, FF12 et 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');
    }
  }

Évidemment, ce n'est pas pareil - si la taille du document change pendant le tri, il faudra faire autre chose. Cependant, d'après mon expérience, cela semble moins étrange dans ces circonstances.

4
DaveJenni

J'ai "corrigé" ceci en utilisant les nouvelles versions de jQuery/jQuery UI.

  • jQuery 1.8.0
  • interface utilisateur jQuery 1.8.23
1
Jorge Morante

Pour les futurs lecteurs Je suis tombé sur un problème similaire dans lequel l’élément auxiliaire a un décalage lorsqu’il glisse à l’intérieur du div défilé d’une boîte de dialogue bootstrap. Lorsque vous relâchez l'objet déplacé, l'animation envoie l'élément d'assistance déplacé vers sa nouvelle position sans tenir compte de la partie défilée de la page, ce qui donne un retour confus aux utilisateurs. 

Pour que les choses continuent à fonctionner avec position: relative et overflow-y: auto dans le conteneur de dialogue, ma solution était: 

1- Ajoutez le décalage scrollTop () au sommet de la marge de l'objet utilitaire dans l'événement de début de tri;

2- enlever le haut de la marge dans l'événement beforeStop

Cela a empêché l'animation d'être désactivée après le déplacement, mais l'objet d'assistance est poussé sous le curseur tout en faisant glisser la partie défilée de la page. Le dernier correctif est 

3- Calculez et définissez la propriété top de l'objet utilitaire lors du glissement (à l'aide de l'événement de tri) par rapport au pointeur et à l'offset du conteneur.

$(...).sortable({
...
start: function (event, ui) {  
    ui.helper.css('margin-top', $("#mybootstrap-dialog").scrollTop()); 
},
beforeStop: function (event, ui){ 
    ui.helper.css('margin-top',0); 
},
sort: function(event, ui) {
    var top = event.clientY - $('#my-sortable-ul').offset().top  -  $("#mybootstrap-dialog").scrollTop();
    ui.helper.css({'top' : top + 'px'});
    }
},
...

});

Aide ça aide

0

Pour les futurs lecteurs avec ce problème . J'ai mis à jour de jqueryui 1.8 à 1.10.3 et le problème a été résolu sans correctifs CSS.

http://jqueryui.com/

J'ai également mis à niveau de jquery 1.8 à 1.10.2

http://jquery.com/

0
Michael J. Calkins

Si vous définissez overflow: auto, Firefox commence à faire glisser l’élément situé sous le pointeur, mais empêche également le défilement automatique de fonctionner correctement. Vous pouvez le voir directement dans l'exemple jQuery Sortable, si vous rendez la fenêtre suffisamment petite pour que le défilement soit nécessaire.

J'avais overflow: scroll sur la balise html, mais même en supprimant cela et (je pense) tous les éléments relatifs contenant ne résolvaient pas totalement le problème (ce qui signifie que le glissement commence correctement et que le défilement automatique fonctionne). J'ai aussi essayé un patch pour renifler mozilla sur _findRelativeOffset (je pense que c'était ça), mais cela n'a pas aidé.

Ce qui m'a aidé dans mon cas d'utilisation était simplement de faire glisser un clone (helper: 'clone' dans le constructeur déplaçable). Pour donner l’impression que le clone n’était pas là, j’ai ajouté les méthodes de démarrage et d’arrêt qui fixent simplement la visibilité à hidden, puis de retour.

J'aurais commenté ci-dessus, mais je n'ai pas encore les points.

0
Dan Chadwick

Pour résumer vos efforts et fournir une solution complète. Ce qui suit semble fonctionner pour Chrome 40+ et 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 );
        }
    }
});
0
Lorenz Lo Sauer

Avait le même problème. Dans mon cas, il n’était pas possible d’utiliser le correctif "overflow: auto". Donc c'est ce que j'ai fait.

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
  }
 }
});

La solution ne s'intéresse pas au navigateur que vous utilisez. Il s'assurera toujours que l'assistant a le même décalage y que la cible lorsque le glissement commence.

0
tappad