I. Traduction▲
Cet article est la traduction la plus fidèle possible de l'article de Andrey Prikaznov, HTML5 Drag and Drop Multiple File Uploader.
Vous pouvez voir un exemple en ligne ou télécharger l'archive de l'exemple.
II. Introduction▲
Ce nouvel article va vous parler du transfert de fichiers en HTML5. Oui, nous avons déjà parlé d'upload en HTML5 dans des articles précédents, mais aujourd'hui, nous allons nous pencher sur un nouvel exemple, le plus intéressant.
L'exemple de cet article va vous permettre de sélectionner les images à télécharger en utilisant le drag & drop (plusieurs images en même temps). De plus, le script va nous permettre d'afficher la progression générale du transfert (en pourcentage et avec le nombre de fichiers restants) et la réponse du serveur (sans l'upload actuel). Nous allons afficher la progression en temps réel dans un canvas. Pour finir, le script permet de télécharger des fichiers non seulement sur notre propre serveur mais sur un autre également (on pourra appeler ça un uploader cross-sites).
III. Étape 1 : le code HTML▲
<div class
=
"container"
>
<div class
=
"contr"
><h2>Glissez - déposez vos fichiers dans la « zone de drop » (maximum cinq fichiers - taille maximale par fichier 256 kb)</h2></div>
<div class
=
"upload_form_cont"
>
<div id
=
"dropArea"
>
Zone de drop</div>
<div class
=
"info"
>
<div>Fichiers restants : <span id
=
"count"
>
0</span></div>
<div>URL de destination : <input id
=
"url"
value
=
"http://www.script-tutorials.com/demos/257/upload.php"
/></div>
<h2>Résultat :</h2>
<div id
=
"result"
></div>
<canvas width
=
"500"
height
=
"20"
></canvas>
</div>
</div>
</div>
<script src
=
"js/script.js"
></script>
Comme vous pouvez le voir, le code se compose de plusieurs éléments principaux : la zone pour le drag and drop à gauche et la zone d'information à droite. Quand on déplace une image dans la zone de gauche, la réponse du serveur s'affiche dans la zone d'information de droite. Faites bien attention à ce que l'URL de destination soit bien renseignée. Dans l'exemple, c'est notre serveur que nous utilisons mais vous pouvez le changer à tout moment.
IV. Étape 2 : le code CSS▲
Nous pouvons maintenant personnaliser notre affichage.
.container
{
overflow:
hidden
;
width:
960
px;
margin:
20
px auto
;
}
.contr
{
background-color:
#212121
;
color:
#FFFFFF
;
padding:
10
px 0
;
text-align:
center
;
border-radius:
10
px 10
px 0
0
;
-moz-border-radius:
10
px 10
px 0
0
;
-webkit-border-radius:
10
px 10
px 0
0
;
}
.upload_form_cont
{
background:
-moz-linear-gradient(
#ffffff
,
#f2f2f2
);
background:
-ms-linear-gradient(
#ffffff
,
#f2f2f2
);
background:
-webkit-gradient(
linear
,
left
top
,
left
bottom
,
color-stop(
0
%,
#ffffff
),
color-stop(
100
%,
#f2f2f2
));
background:
-webkit-linear-gradient(
#ffffff
,
#f2f2f2
);
background:
-o-linear-gradient(
#ffffff
,
#f2f2f2
);
filter:
progid:
DXImageTransform.Microsoft.gradient(
startColorstr='#ffffff'
,
endColorstr='#f2f2f2'
);
-ms-filter:
"progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f2f2f2')"
;
background:
linear-gradient
(
#ffffff
,
#f2f2f2
);
color:
#000
;
overflow:
hidden
;
}
.info
{
background-color:
#EEEEEE
;
border:
1
px solid
#DDDDDD
;
float:
left
;
font-weight:
bold
;
height:
530
px;
margin:
20
px;
position:
relative
;
width:
560
px;
}
.info
>
div {
font-size:
14
px;
font-weight:
bold
;
padding:
10
px 15
px 5
px;
}
.info
>
h2 {
padding:
0
15
px;
}
.info
>
canvas {
margin-left:
15
px;
margin-bottom:
10
px;
}
.info
#url
{
width:
400
px;
}
#dropArea
{
background-color:
#DDDDDD
;
border:
3
px dashed
#000000
;
float:
left
;
font-size:
48
px;
font-weight:
bold
;
height:
530
px;
line-height:
530
px;
margin:
20
px;
position:
relative
;
text-align:
center
;
width:
300
px;
}
#dropArea.hover
{
background-color:
#CCCCCC
;
}
#dropArea.uploading
{
background:
#EEEEEE
url(
loading.gif
)
center
30
% no-repeat
;
}
#result
.s
,
#result
.f
{
font-size:
12
px;
margin-bottom:
10
px;
padding:
10
px;
border-radius:
10
px;
-moz-border-radius:
10
px;
-webkit-border-radius:
10
px;
}
#result
.s
{
background-color:
#77fc9f
;
}
#result
.f
{
background-color:
#fcc577
;
}
V. Étape 3 : le code JavaScript et HTML5▲
// variables
var dropArea =
document
.getElementById
(
'dropArea'
);
var canvas =
document
.querySelector
(
'canvas'
);
var context =
canvas.getContext
(
'2d'
);
var count =
document
.getElementById
(
'count'
);
var destinationUrl =
document
.getElementById
(
'url'
);
var result =
document
.getElementById
(
'result'
);
var list =
[];
var totalSize =
0
;
var totalProgress =
0
;
// initialisation
(
function(
){
// gestionnaires
function initHandlers
(
) {
dropArea.addEventListener
(
'drop'
,
handleDrop,
false);
dropArea.addEventListener
(
'dragover'
,
handleDragOver,
false);
}
// affichage de la progression
function drawProgress
(
progress) {
context.clearRect
(
0
,
0
,
canvas.
width,
canvas.
height);
// effacer le canvas
context.beginPath
(
);
context.
strokeStyle =
'#4B9500'
;
context.
fillStyle =
'#4B9500'
;
context.fillRect
(
0
,
0
,
progress *
500
,
20
);
context.closePath
(
);
// affichage de la progression (mode texte)
context.
font =
'16px Verdana'
;
context.
fillStyle =
'#000'
;
context.fillText
(
'Progression : '
+
Math.floor
(
progress*
100
) +
' %'
,
50
,
15
);
}
// survol lors du déplacement
function handleDragOver
(
event
) {
event
.stopPropagation
(
);
event
.preventDefault
(
);
dropArea.
className =
'hover'
;
}
// glisser déposer
function handleDrop
(
event
) {
event
.stopPropagation
(
);
event
.preventDefault
(
);
processFiles
(
event
.
dataTransfer.
files);
}
// traitement du lot de fichiers
function processFiles
(
filelist) {
if (!
filelist ||
!
filelist.
length ||
list.
length) return;
totalSize =
0
;
totalProgress =
0
;
result.
textContent =
''
;
for (
var i =
0
;
i <
filelist.
length &&
i <
5
;
i++
) {
list.push
(
filelist[
i]
);
totalSize +=
filelist[
i].
size;
}
uploadNext
(
);
}
// à la fin, traiter le fichier suivant
function handleComplete
(
size) {
totalProgress +=
size;
drawProgress
(
totalProgress /
totalSize);
uploadNext
(
);
}
// mise à jour de la progression
function handleProgress
(
event
) {
var progress =
totalProgress +
event
.
loaded;
drawProgress
(
progress /
totalSize);
}
// transfert du fichier
function uploadFile
(
file,
status
) {
// création de l'objet XMLHttpRequest
var xhr =
new XMLHttpRequest
(
);
xhr.open
(
'POST'
,
destinationUrl.
value);
xhr.
onload
=
function(
) {
result.
innerHTML +=
this.
responseText;
handleComplete
(
file.
size);
};
xhr.
onerror
=
function(
) {
result.
textContent =
this.
responseText;
handleComplete
(
file.
size);
};
xhr.
upload.
onprogress =
function(
event
) {
handleProgress
(
event
);
}
xhr.
upload.
onloadstart =
function(
event
) {
}
// création de l'objet FormData
var formData =
new FormData
(
);
formData.append
(
'myfile'
,
file);
xhr.send
(
formData);
}
// transfert du fichier suivant
function uploadNext
(
) {
if (
list.
length) {
count.
textContent =
list.
length -
1
;
dropArea.
className =
'uploading'
;
var nextFile =
list.shift
(
);
if (
nextFile.
size >=
262144
) {
// 256 kb
result.
innerHTML +=
'<div class="f">Fichier trop gros (dépassement de la taille maximale)</div>'
;
handleComplete
(
nextFile.
size);
}
else {
uploadFile
(
nextFile,
status
);
}
}
else {
dropArea.
className =
''
;
}
}
initHandlers
(
);
}
)(
);
La majorité du code est déjà commentée. J'espère que vous pouvez comprendre ce que fait ce code. Voici tout de même quelques explications sur ce que fait ce script JavaScript. Pour commencer, on lie deux gestionnaires d'événements à notre zone de drop : « drop » et « dragover ». Quand on déplace un fichier dans la zone de drop et qu'on ne lâche pas ce dernier, on peut appliquer un style personnalisé à notre zone. Ensuite, quand on lâche le fichier dans la zone, notre script lance la fonction « processFiles » qui met tous les fichiers dans un array et les transfère un par un. Dans le résultat, nous envoyons les données à travers un objet XMLHttpRequest au serveur. Pendant l'envoi des fichiers au serveur, nous affichons la progression totale dans notre canvas.
VI. Étape 4 : le code PHP▲
<?php
// fixe le niveau de rapport d'erreur
if
(version_compare(phpversion(),
'5.3.0'
,
'>='
) ==
1
)
error_reporting(E_ALL &
~
E_NOTICE &
~
E_DEPRECATED);
else
error_reporting(E_ALL &
~
E_NOTICE);
function
bytesToSize1024($bytes
,
$precision
=
2
) {
$unit
=
array
('B'
,
'KB'
,
'MB'
);
return
@
round($bytes
/
pow(1024
,
($i
=
floor(log($bytes
,
1024
)))),
$precision
).
' '
.
$unit
[
$i
];
}
if
(isset($_FILES
[
'myfile'
]
)) {
$sFileName
=
$_FILES
[
'myfile'
][
'name'
];
$sFileType
=
$_FILES
[
'myfile'
][
'type'
];
$sFileSize
=
bytesToSize1024($_FILES
[
'myfile'
][
'size'
],
1
);
echo <<<EOF
<div class="s">
<p>Le fichier :
{
$sFileName
}
a été correctement transféré.</p>
<p>Type :
{
$sFileType
}
</p>
<p>Taille :
{
$sFileSize
}
</p>
</div>
EOF;
}
else
{
echo '<div class="f">Une erreur s
\'
est produite</div>'
;
}
C'est le fichier côté serveur. Ce code ne sert évidemment pas à uploader mais permet de récupérer des informations sur les différents fichiers chargés (que nous afficherons à l'utilisateur à la fin du transfert).
VII. Conclusion▲
Nous avons vu dans cet article comment créer une interface user friendly pour transférer des fichiers multiples en utilisant du drag and drop. En espérant que cet article vous a aidé, n'hésitez pas à consulter les autres articles !
Voir un exemple en ligne / Télécharger l'archive de l'exemple.
VIII. Remerciements▲
Je tiens à remercier Andrey Prikaznov de m'avoir autorisé à traduire son tutoriel.
Je remercie également _Max_ pour sa relecture orthographique.