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.