web-dev-qa-db-fra.com

Comment distinguer si un fichier ou un dossier est glissé avant de le déposer?

J'essaie de détecter si un dossier ou un fichier est déplacé dans les événements dragover ou dragenter.

Par exemple:

Dans l'événement ondrop, il existe un argument appelé MouseEvent, qui contient un champ nommé dataTransfer, où sont répertoriés les fichiers (.files) ou les éléments (.items), en fonction du navigateur, et que je peux lire dans les deux Chrome et Firefox . Toutefois, pour les événements dragover et dragenter, ces champs (.files et .items) sont vides. Le problème est que j’ai besoin de cette information en glissant, pas en laissant tomber.

REMARQUE: Pour les fichiers et les dossiers, event.dataTransfer.types[i] === "Files" est true.

Recherche en arrière plan

J'ai trouvé la réponse suivante pour partiellement répondre à ma question: 

WebKit, et donc Chrome, est assez restrictif pour pouvoir appeler getData. Vous n'êtes pas autorisé à le faire dans dragstart ou dragover. Je pense que c'est le bug canonique.

Mais cette réponse date de 2012 et Je ne trouve pas d'informations actualisées sur le sujet, je recherche donc des informations actualisées à ce sujet.

53
Kristina Kurshakova

TL; DR vous ne pouvez pas :(

Si vous vous demandez pourquoi cette question n'a toujours pas de réponse acceptée, vous pouvez lire cette méta question créée par l'OP, et ma réponse.

Fichier dragdrop en HTML5

J'ai effectué des recherches dans de nombreuses documentations sur ce sujet et l'ai testé par moi-même sur différents navigateurs. J'ai donc décidé de résumer ici tout ce que je sais sur le glisser-déposer.

Glisser

Lorsque vous faites glisser un fichier, vous pouvez utiliser certains écouteurs, tels que:

  • dragenter
  • dragover
  • dragend
  • dragleave

Étant donné qu'il s'agit d'événements drag, la propriété files de event.dataTransfer aura soit length == 0, soit sera vide (null).

Vous ne pouvez pas lire les détails des fichiers dans un événement glisser et vous ne pouvez pas vérifier s'il s'agit de dossiers. Ce n'est pas un bug, c'est une mesure de sécurité.

Imaginez que vous puissiez lire des fichiers lors d'un événement glisser: vous pourrez tout lire même si l'utilisateur ne veut pas télécharger de fichiers sur votre site. Cela n'aurait aucun sens, sérieusement. Imaginez que vous faites glisser un fichier de votre bureau vers un autre dossier et que vous le glissiez accidentellement sur une page Web: maintenant, la page Web lit votre fichier et stocke vos informations personnelles sur son serveur ... _/cela constituerait une faille de sécurité énorme.

Cependant, vous pourrez toujours détecter si l'utilisateur fait glisser des fichiers (et par fichiers, j'entends aussi les dossiers, car les dossiers sont des fichiers) ou non en effectuant une itération sur le tableau event.dataTransfer.types. Vous pouvez créer une fonction qui vérifie si l'événement glisser contient des fichiers, puis l'appeler dans le gestionnaire d'événements.

Exemple:

function containsFiles(event) {
    if (event.dataTransfer.types) {
        for (var i=0; i<event.dataTransfer.types.length; i++) {
            if (event.dataTransfer.types[i] == "Files") {
                return true;
            }
        }
    }

    return false;
}

function handleDragEnter(e) {
    e.preventDefault();
    if (containsFiles(e)) {
        // The drag event contains files
        // Do something
    } else {
        // The drag event doesn't contain files
        // Do something else
    }
}

Goutte

Lorsque vous déposez un fichier dans drop <div> (ou tout élément que vous utilisez en tant que dropzone), vous utiliserez un écouteur pour l'événement drop pour lire certaines propriétés de fichier telles que le nom, la taille, le type et la date de dernière modification.

Pour détecter si un fichier est un dossier, vous allez:

  1. Vérifiez si le fichier a type == "", car les dossiers n'ont pas de type.
  2. Vérifiez si la taille du fichier est un multiple de 4096: size%4096 == 0, car les dossiers ont toujours une taille multiple de 4096 octets (ce qui correspond à 4 Ko).

Exemple:

function handleDrop(e) {
    e.stopPropagation();
    e.preventDefault();

    var files = e.dataTransfer.files;

    for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
        if (!f.type && f.size%4096 == 0) {
            // The file is a folder
            // Do something
        } else {
            // The file is not a folder
            // Do something else
        }
    }
}

KNOWN Issue: Étant donné que les dossiers sont en fait des fichiers, c'est le seul moyen de les distinguer d'un autre type de fichier. Bien que cette méthode ne vous donne pas la certitude absolue qu'un fichier est un dossier: il peut s'agir d'un fichier sans extension et avec une taille de 0 ou exactement N x 4096B.


Exemples de travail

Voici quelques exemples de travail pour voir ce que j'ai dit ci-dessus en action et le tester vous-même. Avant de les exécuter, assurez-vous que votre navigateur prend en charge les fonctions de glisser-déposer . S'amuser:

85
Marco Bonelli

Ceci est un travail sur Dropping -on drop event- (veuillez noter que cela ne fonctionne pas sur un événement dragover):

isDraggedItemIsFile = function(e) {
// handle FF
if (e.originalEvent.dataTransfer.files.length == 0) {
    return false;
}
// handle Chrome
if (e.originalEvent.dataTransfer.items) {
    if (typeof (e.originalEvent.dataTransfer.items[0].webkitGetAsEntry) == "function") {
        return e.originalEvent.dataTransfer.items[0].webkitGetAsEntry().isFile;
    } else if (typeof (e.originalEvent.dataTransfer.items[0].getAsEntry) == "function") {
        return e.originalEvent.dataTransfer.items[0].getAsEntry().isFile;
    }
}
return true;
};

$forms.on('drop', function(e) {
        if (isDraggedItemIsFile(e)) {
            // do something if file
        } else{
           // is directory
        }
    });

Testé sur FF V49, Chrome V55, Edge V25

0
Anas

J'ai pu obtenir la totalité du type Mimetype de la chose étant traîné sur ma page. Le type MIME semble être vide pour les dossiers, alors vous pouvez peut-être le distinguer de cette façon.

Code partiel (extrait de React):

function handleDragOver(ev: DragEvent) {
    ev.preventDefault();
    ev.dataTransfer!.dropEffect = 'copy';
    console.log(Array.from(ev.dataTransfer.items).map(i => [i.kind,i.type].join('|')).join(', '));
}

document.addEventListener('dragover',handleDragOver);

La sortie ressemble à:

file|image/x-icon, file|image/jpeg, file|application/vnd.ms-Excel

Lorsque je fais glisser 3 fichiers sur ma page.

Vous ne savez pas si cela ne fonctionne que sur localhost, je ne l'ai pas encore téléchargée, mais cela fonctionne totalement.

Documents MDN sur DataTransferItem

0
mpen

Vous pouvez séparer des fichiers de dossiers en utilisant FileReader ou avec webkitGetAsEntry ()

WebkitGetAsEntry () n'est pas pris en charge par ie11, alors gardez cela à l'esprit!

Le code ressemblera à ceci:

 onDrop(event) {
    let files = event.dataTransfer ? event.dataTransfer.files : 'null';

    for(let i = 0, file; file = files[i]; i++) {
       var reader = new FileReader();

       reader.onload = function (e) {
           console.log('it is a file!');
       };
       reader.onerror = function (e) {
          console.log('it is a folder!');
       };

       reader.readAsText(file);
    }

}
0
Kaloyan Stamatov