Html 5 4ª ed

Page 1


WEB STORAGE

7.4.3

199

FILE API

A File API foi introduzida para nos fornecer maior flexibilidade no acesso ao conteúdo de ficheiros a partir de uma página HTML. Por predefinição, o acesso a um ficheiro a partir de uma página HTML não é permitido. Afinal, nenhum utilizador teria interesse em ver uma página HTML efetuar um scanning do seu disco sem que ele tivesse autorizado a realização dessa operação. Portanto, a leitura de um ficheiro é sempre uma operação que deve ser explicitamente iniciada por um utilizador final. É por isso que o acesso a um ficheiro a partir de uma página HTML é geralmente feito através de um controlo input do tipo file. Atualmente, este controlo permite mesmo que um utilizador final efetue a seleção de vários ficheiros (para isso, temos apenas de anotá-lo com o atributo multiple). O acesso aos ficheiros selecionados por um utilizador é sempre feito através da propriedade files, que devolve um objeto do tipo FileList. Este objeto pode ser visto como um array, onde cada entrada referencia um objeto do tipo File, que representa programaticamente um ficheiro. Como seria de esperar, o número de elementos mantido neste array pode ser recuperado através da propriedade length. O excerto seguinte (cap07/fileapi01.html) mostra como podemos apresentar alguma informação genérica sobre os ficheiros selecionados pelo utilizador: HTML

<!DOCTYPE html > <html lang="pt-pt"> <head> <meta charset="utf-8"> <title>Acesso aos ficheiros selecionados por um utilizador</title> </head> <body> <p> <input type="file" id="ficheiros" multiple="multiple" >

© FCA – Editora de Informática


200

HTML5

</p> <p> <input type="button" value="imprimir" id="imprimir"> </p> <div id="conteudos"> </div> </body> <script> function imprimeInformacao() { var conteúdos = document.getElementById("conteudos"); var ficheiros = document.getElementById("ficheiros").files; conteudos.innerHTML = "<p>Total ficheiros selecionados:" + ficheiros.length + "</p>"; for(var i = 0; i < ficheiros.length; i++){ var ficheiro = ficheiros[i]; conteudos.innerHTML += ficheiro.name + " modificado em " + ficheiro.lastModifiedDate +"<br>"; } } document.getElementById ("imprimir") .addEventListener( "click", imprimeInformacao); </script> </html>

Quando

o

utilizador

clica

no

botão

imprimir,

a

função

imprimeInformacao indica o número de ficheiros selecionados no controlo input e imprime o nome (propriedade name) e a data de última modificação (propriedade lastModifiedDate) de cada um desses ficheiros.

A figura seguinte ilustra os resultados obtidos quando executamos esta página no Internet Explorer:

© FCA – Editora de Informática


WEB STORAGE

201

FIGURA 7.5 – Impressão de informação genérica sobre ficheiros

Para além do nome e data de última modificação, o objeto que representa o ficheiro permite-nos ainda obter o seu tamanho em bytes (propriedade size) e o seu tipo (propriedade type). Neste caso, o tipo de um ficheiro é sempre representado por uma string (em minúsculas) compatível com os valores indicados pelo RFC2046 (http://tools.ietf.org/html/rfc2046). O excerto seguinte ilustra o código necessário à alteração do exemplo anterior para que esta informação seja apresentada ao utilizador final: JavaScript

for( var i = 0; i < ficheiros.length; i++){ var ficheiro = ficheiros[i]; conteudos.innerHTML += ficheiro.name + " (tipo " + ficheiro.type + ") <br>"+ " modificado em " + ficheiro.lastModifiedDate + "<br>" + " tamanho: " + ficheiro.size + " bytes<p>"; }

7.4.3.1 UPLOAD DE FICHEIROS

Depois de obtermos uma referência para um objeto File, podemos efetuar o seu upload através de AJAX. Para isso, temos de recorrer ao objeto FormData, que foi introduzido pela especificação XMLHttpRequest (Level 2). Este objeto representa programaticamente um formulário HTML e permite a adição de pares chave/valor que representam os dados que devem ser enviados para o servidor.

© FCA – Editora de Informática


202

HTML5

O excerto seguinte ilustra o uso deste objeto: JavaScript

var form = new FormData(); form.append("nome", "Luis");

O exemplo seguinte ilustra o código típico usado numa operação de upload: JavaScript

var form = new FormData(); form.append("nome", "luis"); form.append("pic", file );//supor que file referencia um ficheiro var xhr = new XMLHttpRequest(); xhr.onload = function(){ //feedback de operação completa } xhr.open("post", "/submit", true); xhr.send(form);

Ao detetar a passagem do objeto form ao método send, o browser encarrega-se de adicionar todos os cabeçalhos necessários à correta submissão dos dados. Ou seja, para o servidor, esta submissão possui exatamente o mesmo aspeto que uma submissão efetuada através de um formulário HTML tradicional, permitindo-nos, assim, reutilizar a mesma handler de backoffice para submissões efetuadas através de um formulário HTML ou através de um pedido AJAX. Tipos das propriedades size e type Na realidade, estas propriedades (size e type) são introduzidas pela interface Blob que, por sua vez, é implementada pelo objeto File. Para além das propriedades, a interface Blob introduz ainda um conjunto de métodos úteis. O método slice pode ser usado para devolver um novo Blob, delimitado pelo primeiro e segundo parâmetros, cujo tipo é indicado através do terceiro parâmetro (note-se que todos os parâmetros são opcionais). Por sua vez, o método close encarrega-se de "encerrar" o blob atual, impedindo a realização futura de eventuais operações de leitura.

© FCA – Editora de Informática


WEB STORAGE

203

7.4.3.2 ESCONDER O CONTROLO FILE

Nem sempre é possível acomodarmos um controlo input do tipo file na interface gráfica de uma página. Nesses casos, e como o acesso aos ficheiros mantidos no computador é tipicamente iniciado pelo utilizador a partir de um clique efetuado sobre um controlo desse tipo, podemos esconder o controlo através da aplicação de um estilo CSS. Para ilustrarmos esta estratégia, vamos modificar a página anterior, fazendo com que a apresentação do diálogo de escolha de ficheiros seja efetuada a partir de um clique sobre uma âncora que foi adicionada à página. O excerto seguinte (retirado da página cap07/file02.html) apresenta as principais alterações efetuadas à página inicial: HTML

<!DOCTYPE html > <html lang="pt-pt"> <head> <meta charset="utf-8"> <title>Acesso aos ficheiros através de drag-drop</title> <style type="text/css"> #ficheiros{ display: none; } </style> </head> <body> <body>

<p> <a href="#" id="escolher" >Escolher ficheiros</a>

<input type="file" id="ficheiros" multiple="multiple"> </p> <p> <input type="button" value="imprimir" id="imprimir"

/>

</p>

© FCA – Editora de Informática


204

HTML5 < div id="conteudos">

</body>

</div>

<script> //código de impressão removido function mostraDialogo(){ document .getElementById ("ficheiros").click(); } document.getElementById("imprimir") .addEventListener("click", imprimeInformacao); document.getElementById("escolher") .addEventListener("click", mostraDialogo); </script>

</body> </html>

Como é possível observar, o controlo file é escondido através da definição de uma regra CSS que atribui o valor none ao estilo display (a atribuição deste valor faz com que o controlo não ocupe qualquer espaço na página). Para além disso, configurámos ainda a âncora para invocar o método mostraDialogo em resposta a um clique efetuado pelo utilizador.

7.4.3.3 OPERAÇÕES DE DRAG-N-DROP

Até aqui, o acesso aos ficheiros tem sido sempre efetuado através do controlo input type="file". As versões mais recentes dos browsers permitem, contudo, uma outra opção: aceder aos ficheiros arrastados para o browser através do uso de operações de drag-n-drop. A concretização deste cenário obriga-nos a definir uma zona que desempenha o papel de alvo e a tratar um par de eventos que permitem influenciar o comportamento do browser e obter as referências para os ficheiros arrastados. O excerto seguinte ilustra o código necessário ao suporte deste cenário: JavaScript

<script> function paraPropagacao(e) {

© FCA – Editora de Informática


WEB STORAGE

205

e.stopPropagation(); e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; } function drop(e) { e.stopPropagation(); e.preventDefault(); var dt = e.dataTransfer ; var ficheiros = dt.files; var conteudos = document.getElementById("conteudos"); for(var i = 0; i < ficheiros.length; i++){ var ficheiro = ficheiros[i]; conteudos.innerHTML += ficheiro.name + " (tipo " + ficheiro.type + ") <br>" + " modificado em " + ficheiro.lastModifiedDate + "<br>" + "

tamanho: " + ficheiro.size + " bytes<p>";

} } var div = document.getElementById ("alvo"); div.addEventListener("dragover", paraPropagacao, false); div.addEventListener("dragenter", paraPropagacao, false); div.addEventListener("drop", drop, false); </script>

Neste caso, o papel de alvo é desempenhado por um elemento div. Ao detetar o arrastamento de um item sobre a área delineada pelo elemento div, o browser gera o evento dragenter. Neste exemplo, o tratamento do evento implica o cancelamento do seu comportamento predefinido e a modificação do ícone usado nesta operação de drag-n-drop. Quando o utilizador larga o ficheiro sobre o div, o browser gera o evento drop. A partir deste evento, é possível recuperarmos os ficheiros arrastados através do acesso à propriedade files do objeto DataTransfer, que, por sua vez, é recuperado a partir do objeto que representa esse evento.

© FCA – Editora de Informática


206

HTML5

7.4.3.4 LEITURA DE FICHEIROS

Até agora, os nossos exemplos concentraram-se apenas em apresentar estratégias que mostram as opções que permitem aceder a ficheiros. Como vimos, um ficheiro existente no disco é representado programaticamente por um objeto File. Este tipo permite-nos apenas recuperar alguma informação básica sobre esse ficheiro (ex.: nome do ficheiro) e não disponibiliza nenhum método ou propriedade que nos permita aceder aos seus conteúdos. De acordo com a especificação, a recuperação dos conteúdos de um ficheiro (isto é, a leitura dos seus bytes) fica a cargo de um outro objeto: estamos a referir-nos ao objeto FileReader. Na prática, este objeto disponibiliza um conjunto de métodos que se encarregam de ler assincronamente um ficheiro e de gerar vários eventos que sinalizam o progresso dessa operação. O uso mais simples do objeto faz com que apenas tenhamos de nos preocupar com o evento load, que pode ser usado para aceder aos conteúdos do ficheiro que foi carregado em memória. Atualmente, a leitura dos conteúdos pode ser iniciada através de um dos métodos seguintes: readAsText: devolve os conteúdos do ficheiro em texto simples, codi-

ficado por predefinição em UTF-8 (útil quando pretendemos recuperar os conteúdos de um ficheiro de texto); readAsDataURL: retorna uma string com os conteúdos do ficheiro no

formato data URI (http://en.wikipedia.org/wiki/Data_URI_scheme); readAsArrayBuffer: devolve um objeto do tipo ArrayBuffer que

permite aceder aos bytes do ficheiro (indicado quando necessitamos de trabalhar com, por exemplo, os bytes de uma imagem). Cada um destes métodos efetua a leitura de forma assíncrona, pelo que a recuperação dos conteúdos no formato indicado deve ser feita apenas em resposta ao evento load. Assim, os conteúdos do ficheiro podem ser obtidos a partir da propriedade target.result do objeto que é passado à função que trata o evento. As várias fases associadas à recuperação dos conteúdos efetuada pelo objeto FileReader são sinalizadas pelos eventos loadstart (marca o início do processo de carregamento), progress (gerado várias vezes durante o carregamento dos conteúdos), error (gerado para sinalizar a ocorrência de um erro), © FCA – Editora de Informática


WEB STORAGE

207

abort (sinaliza o cancelamento da operação de leitura em resposta à invocação do método abort), load (gerado apenas quando os conteúdos são carregados com sucesso) e loadend (sinaliza o final do processo de carregamento).

Para ilustrarmos o uso básico deste objeto, vamos criar uma página simples que se limita a adicionar as imagens que são arrastadas por drag-n-drop e libertadas sobre um elemento div. O excerto seguinte apresenta o código usado (cap07/file04.htm): HTML

<!DOCTYPE html > <html lang="pt-pt"> <head> <meta charset="utf-8"> <title>Renderização de imagens em drag-n-drop</title> <style type="text/css"> #alvo{ height:150px; background-color: lightgreen; } .thumbnail{ height: 75px; border: solid 1px red; margin: 5px; } </style> </head> <body> <div id="alvo" dropzone="copy"> Arraste os ficheiros para aqui</div> <div id="conteudos"></div> <script> function paraPropagacao(e) { e.stopPropagation(); e.preventDefault(); © FCA – Editora de Informática


208

HTML5 e.dataTransfer.dropEffect = 'copy'; } function drop(e) { e.stopPropagation(); e.preventDefault();

var dt = e.dataTransfer; var ficheiros = dt.files; for(var i = 0; i < ficheiros.length;ii++){ var ficheiro = ficheiros[i]; if(!ficheiro.type.match(/image.*/)){ return; } var reader = new FileReader(); reader.addEventListener("load",printImage); reader.readAsDataURL(ficheiro); } } var conteudos = document.getElementById("conteudos"); function printImage(e) { var imgStr = "<img class='thumbnail' src='" + e.target.result+ "' title='" + e.target.name + "' />"; conteudos.innerHTML += imgStr; } var div = document.getElementById("alvo"); div.addEventListener("dragover", paraPropagacao, false); div.addEventListener("dragenter", paraPropagacao, false); div.addEventListener("drop", drop, false); </script> </body> </html> © FCA – Editora de Informática


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.