Scintillement par glisser-déposer jQuery en survol (Webkit uniquement)

Problème

Je viens de terminer la mise en œuvre d’une fonctionnalité permettant aux utilisateurs de faire glisser des fichiers dans le navigateur et de les déposer sur un plug-in de téléchargement de fichier compatible, qui traite la suppression.

Cependant, afin de donner aux utilisateurs un indice qu’ils peuvent même déposer des choses en premier lieu, j’ai implémenté un événement de dragoverdragover pour montrer une div qui dit quelque chose qui s’apparente à “Drop Here”. Ceci, à son tour, masque la div qui a le bouton “Choisir un fichier …” et le remplace jusqu’à ce que l’utilisateur cesse de faire glisser.

Mais il semble que lorsque j’implémente cela, glisser sur la zone cible provoque un scintillement. Pour être clair:

  • div avec l’interface “Choose File” est affichée.
  • Élément glissé (ou texte sélectionné glissé); “Drop here” est affiché.
  • L’élément traîné sur la zone “Déposer ici”; le scintillement commence.

Aditionellement:

  • Il n’y a pas de problème dans Opera 12 ou Firefox 16.
  • Le problème est flagrant dans Chrome 23 et Safari 5.
  • La question est en partie là dans IE 9 (IE 10 non testé); il clignote pendant environ 5 secondes, puis s’arrête.

jsFiddle

(Attention: le violon est très brut.)

Il suffit de sélectionner une partie du texte et de le faire glisser sur la zone bleue pour voir ce qui se passe. il sera évident le comportement qu’il ne devrait pas être exhibant.

Code utilisé dans le violon

 var $dropTarget = $("#container"); $(document).bind("dragover", function(e) { if ($dropTarget.hasClass("highlight")) return; $dropTarget.addClass("highlight"); $dropTarget.find("[name='drop']").show(); $dropTarget.find("[name='drag']").hide(); }).bind("dragleave drop", function(e) { if (!$dropTarget.hasClass("highlight")) return; $dropTarget.removeClass("highlight"); $dropTarget.find("[name='drop']").hide(); $dropTarget.find("[name='drag']").show(); });​ 

Ma solution …?

Pour être honnête, je n’ai aucune idée de ce qu’il faut essayer. Il n’y a pas de documentation exhaustive sur le comportement de dragover ou dragleave , et je ne sais même pas pourquoi cela se produit, je ne peux même pas commencer à le déboguer. Je pense que les dragover ne devraient être déclenchés qu’une seule fois, mais même le fait de le faire glisser autour de l’écran ne fait que le déclencher encore et encore.

J’ai examiné le comportement de glisser-déposer de Google Images et de Google Contacts, mais leur code est complètement illisible et illisible et je ne trouve même pas le comportement de “glisser” spécifié.

Alors, y a-t-il une solution à ce comportement apparemment étrange? S’il s’agit d’un bogue dans WebKit, dont je soupçonne l’existence, existe-t-il une solution de contournement et / ou un hack génial que je peux utiliser?

Merci à tous pour leur temps!

Après plus d’une heure de nettoyage, j’ai trouvé quelqu’un qui avait un problème similaire . Il semble que Chrome et Safari (5, au moins) tirent en dragleave lorsqu’ils entrent dans un élément enfant (et apparemment, lors de toute modification apscope à cet élément, y compris les enfants montrés / cachés).

La solution consiste à vérifier si pageX et pageY sont égaux à 0 dans dragleave (mais pas drop ).

 var $dropTarget = $("#container"); $(document).bind("dragenter", function(e) { if (e.target == this) { return; } $dropTarget.addClass("highlight"); $dropTarget.find("[name='drop']").show(); $dropTarget.find("[name='drag']").hide(); }).bind("dragleave", function(e) { if (e.originalEvent.pageX != 0 || e.originalEvent.pageY != 0) { return false; } // Could use .sortinggger("drop") here. $dropTarget.removeClass("highlight"); $dropTarget.find("[name='drop']").hide(); $dropTarget.find("[name='drag']").show(); }).bind("drop", function(e) { $dropTarget.removeClass("highlight"); $dropTarget.find("[name='drop']").hide(); $dropTarget.find("[name='drag']").show(); });​ 

J’ai trouvé qu’avec la solution d’Eric, si je glissais hors de l’écran sous Win10 Google Chrome (sur une autre fenêtre) après avoir utilisé cette solution, cela ne fonctionnait pas pour moi. Changer le conditionnel en un AND a plutôt fonctionné.

 var $dropTarget = $("#container"); $(document).bind("dragenter", function(e) { if (e.target == this) { return; } $dropTarget.addClass("highlight"); $dropTarget.find("[name='drop']").show(); $dropTarget.find("[name='drag']").hide(); }).bind("dragleave", function(e) { if (e.originalEvent.pageX != 0 || e.originalEvent.pageY != 0) { return false; } // Could use .sortinggger("drop") here. $dropTarget.removeClass("highlight"); $dropTarget.find("[name='drop']").hide(); $dropTarget.find("[name='drag']").show(); }).bind("drop", function(e) { $dropTarget.removeClass("highlight"); $dropTarget.find("[name='drop']").hide(); $dropTarget.find("[name='drag']").show(); });​