Apesar do HTML 5 ainda não ter sido totalmente especificado e por isso ainda não ter sido liberado pela W3C, ele já está sendo adotado por diversos navegadores e com isso várias aplicações web estão fazendo uso destes novos recursos.
Neste artigo irei mostrar uma forma de realizar upload de arquivos utilizando a File API do HTML 5 simplesmente arrastando um arquivo do desktop em um área pré-determinada da página. Além disso, também será utilizado o FileReader que possibilita o ler o conteúdo do arquivo que é carregado do file system.
ATENÇÃO: Se você está visualizando este post através do feed, eu peço que visite a página do conteúdo no site para ver o exemplo funcionando em seu navegador.
No exemplo, um arquivo arrastado a partir do desktop é carregado pelo navegador e é exibida no frame. É um exemplo simples mas que exemplifica bem o uso desses novos recursos disponíveis pelo Html 5. Se o arquivo arrastado não for uma imagem nada será exibido.
Neste exemplo iremos utilizar uma simples div para delimitarmos a área em que o arquivo será arrastado. E colocaremos um elemento span para avisarmos nosso usuário que o arquivo deve ser arrastado para este lugar.
<html>
<head>
<link href="html5-fileapi.css" media="all" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="example-content">
<div id="frame">
<div id="image-area">
<span id="drop-message"> Arraste a imagem aqui </span>
</div>
<span id="title"> Digite um titulo </span>
</div>
</div>
</body>
<script src="html5-file-upload-code.js" type="text/javascript"></script>
</html>
O estilo utilizado no exemplo é bem simples e pode ser visto logo abaixo:
# example-content { text-align: center; }
# frame { background-color: #000; color: #fff; margin: 50px; width: 400px; height: 450px; padding: 50px; }
# image-area { width: 100%; border: 1px dotted #fff; padding-top: 50%; padding-bottom: 50%; margin-bottom: 15px; overflow:hidden; }
.hover { border: 1px solid #fff !important; }
Abaixo irei colocar o código comentado que será utilizado neste exemplo. Há bastante comentários no código, mas como de costume, quero reforçar que qualquer dúvida utilize o sistema de comentários do site.
// Criação da nossa "classe" de controle.
// Não entrarei neste detalhe aqui, mas por favor,
// se você ouvir alguém falar que javascript é uma
// linguagem orientada a objetos, no mínimo, não
// acredite nele. Javascript é uma linguagem prototipada.
// Essa maneira de programar javascript é uma preferencia
// minha. Prefiro este estilo a criar várias funções perdidas.
function FileFrame(fileArea, fileTitle) {
var self = this;
this.fileArea = fileArea;
this.fileTitle = fileTitle;
this.init = function() {
// Registrando eventos de drag and drop
self.fileArea.addEventListener("dragleave", self.dragHover, false);
self.fileArea.addEventListener("dragover", self.dragHover, false);
self.fileArea.addEventListener("drop", self.drop, false);
};
this.dragHover = function(e) {
// Impede possíveis tratamentos dos arquivos
// arrastados pelo navegador, por exemplo, exibir
// o conteudo do mesmo.
e.stopPropagation();
e.preventDefault();
// Quando o arquivo está sobre área alteramos o seu estilo
self.fileArea.className = (e.type == "dragover" ? "hover" : "");
};
this.drop = function(e) {
self.dragHover(e);
// Volta um array com os arquivos arratados,
// porém neste exemplo iremos tratar apenas
// o primeiro arquivo
self.file = e.dataTransfer.files[0];
// Recupera nome do arquivo
self.fileTitle.innerHTML = self.file.name;
self.read(self.file);
// Neste ponto podemos implementar uma função para
// enviar os arquivos via ajax.
// Irei deixar um exemplo, qualquer dúvida eu peço
// que utilize o sistema de comentários do site.
/*
self.sendFile(self.file);
*/
};
// Esse método irá ler o arquivo na memória,
// depois iremos mostrá-lo no nosso frame
this.read = function(file) {
// Iremos ler apenas imagens nesse exemplo
// e iremos exibi-lo no frame
if (file.type.match('image.*')) {
var reader = new FileReader();
// Callback que será executado após a leitura do arquivo
reader.onload = function(f) {
self.fileArea.innerHTML = "";
self.fileArea.setAttribute("style", "padding: 0px !important;");
// Criação do elemento que será utilizado para exibir a imagem
var img = document.createElement("img");
img.setAttribute("src", f.target.result);
img.setAttribute("height", "350");
self.fileArea.appendChild(img);
}
// Irá ler o arquivo para ser acessado através de uma url
reader.readAsDataURL(file);
}
}
// Essa função pode ser utilizada como
this.sendFile = function(file) {
// Criaremos um formulário
var f = new FormData();
// Passando o arquivo para o formulário
f.append("file", file);
// Chamada async para realizar o upload da imagem
var request = new XMLHttpRequest();
request.open("POST", "", true);
request.send(f);
request.onreadystatechange=function(){
// Término do envio do formulário
if(request.readyState==4) {
}
}
};
}
// Recupera a div que conterá a imagem
// e o span com o título de nosso arquivo
var area = document.getElementById("image-area");
var title = document.getElementById("title");
var fileFrameArea = new FileFrame(area, title);
fileFrameArea.init();
Infelizmente o uso deste tipo de recurso em produção ainda dever ser utilizado em aplicações bastante especificas ou devemos também criar alternativas a elas já que uma bela parcela de usuários ainda estão utilizando navegadores que não suportam esse tipo de recurso. Mas é legal ver o que está por vir.
Os arquivos utilizados neste exemplo podem ser encontrados no repositório do blog no github.