DESENVOLVIMENTO DE APLICAÇÕES WEB UTILIZANDO A
Transcrição
DESENVOLVIMENTO DE APLICAÇÕES WEB UTILIZANDO A
Paulo de Rezende Pinatti 0650410 DESENVOLVIMENTO DE APLICAÇÕES WEB UTILIZANDO A ABORDAGEM AJAX Jaguariúna 2007 Paulo de Rezende Pinatti 0650410 DESENVOLVIMENTO DE APLICAÇÕES WEB UTILIZANDO A ABORDAGEM AJAX Monografia apresentada à disciplina Trabalho de Graduação III, do curso de Ciência da Computação da Faculdade de Jaguariúna, sob a orientação do Prof. Peter Jandl Jr, como exigência parcial para a conclusão do curso. Jaguariúna 2007 PINATTI, Paulo de Rezende. Desenvolvimento de Aplicações Web Utilizando a Abordagem Ajax. Monografia defendida e aprovada na FAJ em 10 de dezembro de 2007 pela banca examinadora constituída pelos professores: __________________________________________ Prof. Peter Jandl Jr. FAJ __________________________________________ Prof. José Arnaldo Geraldini Nunes FAJ __________________________________________ Prof. Valdecir de Oliveira Pereira POLICAMP DEDICATÓRIA Dedico esse trabalho à minha família, na qual incluo minha noiva, pela dedicação com que fui educado e pela maravilhosa oportunidade de partilhar sua convivência, fatos que propiciaram me tornar a pessoa que sou hoje. Espero durante a minha vida ser capaz de retribuir a tudo que aprendi e ainda hoje aprendo com eles e que contribui para a minha formação como ser humano. PINATTI, Paulo de Rezende. Desenvolvimento de Aplicações Web Utilizando a Abordagem Ajax. 2007. Monografia (Bacharelado em Ciência da Computação) – Curso de Ciência da Computação da Faculdade de Jaguariúna, Jaguariúna. RESUMO Desde o início da utilização da Internet para fins comerciais cresce a cada dia a quantidade de recursos e serviços disponibilizados através da rede. As aplicações web são as responsáveis por grande parte desses serviços, e seu modelo tradicional de funcionamento não é capaz de atender à crescente demanda por aplicações mais funcionais e interativas, que possam prover uma experiência de uso mais agradável ao usuário e suportar funcionalidades que se tornam cada vez mais complexas. A utilização de um conjunto de determinadas tecnologias com a finalidade de atender tais necessidades designa o termo conhecido como Ajax, ou Asynchronous JavaScript + XML, estabelecendo uma nova maneira de se desenvolver aplicações web. O presente trabalho tem por objetivo analisar a utilização do modelo Ajax como solução a ser adotada no desenvolvimento de aplicações web que sobreponham o modelo tradicional, propiciando uma rica experiência de uso ao usuário. Para isso é inicialmente realizada uma análise comparativa entre os modelos tradicional e Ajax, seguida de uma abordagem das tecnologias empregadas como HTML, CSS, XML, DOM e JavaScript. Também é feita a implementação de um protótipo utilizando a técnica, seguida de uma análise de seus resultados. Ao final do estudo são apresentadas as conclusões que consideram a abordagem Ajax capaz de atender o objetivo especificado, as alternativas para a solução de algumas desvantagens encontradas na adoção da técnica e também seu contexto de utilização. Palavras-chave: Aplicações web, experiência de uso, Ajax, JavaScript. ABSTRACT Since the beginning of the Internet use for commercial purposes, the quantity of resources and services offered through the network grows each day. Web applications are responsible for a huge part of these services, and its traditional working model is not capable of satisfying the increasing demand for more functional and interactive applications that can provide a more pleasant use experience to the user and support functionalities that become more and more complex. The utilization of a certain group of technologies with the purpose of satisfying the mentioned needs designates the term known as Ajax, or Asynchronous JavaScript + XML, establishing a new way to develop web applications. The objective of this work is to analyze the use of the Ajax model as a solution to be adopted for the development of web applications that overlap the traditional model, offering to the user a rich use experience. In order to do so, at the beginning of this work it is done a comparative analysis between the traditional and Ajax models, followed by an approach of the technologies used such as HTML, CSS, XML, DOM and JavaScript. Also, a prototype has been implemented employing the technique, followed by an analysis of its results. At the end of this work, conclusions that consider the Ajax approach capable of accomplishing the specified objective are presented, as well as alternatives for solutioning some disadvantages found when adopting the technique and also its utilization scope. Keywords: Web applications, use experience, Ajax, JavaScript. 6 SUMÁRIO LISTA DE SIGLAS .......................................................................................................... 7 LISTA DE FIGURAS ....................................................................................................... 8 LISTA DE CÓDIGOS E TABELAS .................................................................................. 9 1. INTRODUÇÃO ............................................................................................................ 10 1.1 Objetivo ..................................................................................................................... 12 1.2 Estrutura do trabalho ................................................................................................ 12 2. MODELOS TRADICIONAL E AJAX DE APLICAÇÕES WEB .................................... 14 2.1 Modelo tradicional de aplicações web ...................................................................... 17 2.2 Modelo Ajax de aplicações web ............................................................................... 18 2.3 Tecnologias .............................................................................................................. 20 3. HTML/XHTML E CSS ................................................................................................. 23 3.1 O que são HTML/XHTML ......................................................................................... 24 3.2 Web Standards ......................................................................................................... 28 3.3 Cascading Style Sheets (CSS) ................................................................................. 30 4. JAVASCRIPT .............................................................................................................. 34 4.1 Sintaxe ...................................................................................................................... 35 4.2 Browser Object Model .............................................................................................. 39 4.3 Eventos ..................................................................................................................... 45 4.4 O objeto XMLHttpRequest ........................................................................................ 53 5. DOCUMENT OBJECT MODEL E XML ...................................................................... 59 5.1 Documento XML ...................................................................................................... 59 5.2 Funcionamento do DOM .......................................................................................... 64 5.3 DOM e XML na abordagem Ajax ............................................................................. 76 6. PROTÓTIPO .............................................................................................................. 82 6.1 Funcionamento e estrutura ...................................................................................... 83 6.2 Recursos .................................................................................................................. 86 6.3 Resultados ............................................................................................................... 92 7. CONCLUSÕES .......................................................................................................... 93 7.1 Frameworks ............................................................................................................. 95 7.2 Considerações finais ................................................................................................ 96 8. REFERÊNCIAS BIBLIOGRÁFICAS ........................................................................... 98 7 Lista de Siglas Ajax - Asynchronous JavaScript + XML API - Application Programming Interface ARPAnet - Advanced Reserch Projects Agency Network of the Departament of Defense ASP - Active Server Pages BOM - Browser Object Model CERN - Conseil Européen pour la Recherche Nucléaire CGI - Common Gateway Interface CSS - Cascading Style Sheets DOM - Document Object Model DTD - Document Type Definition ECMA - European Computer Manufacturers Association GPL - General Public License GWT - Google Web Toolkit HTML - HyperText Markup Language HTTP - HyperText Transfer Protocol IE - Internet Explorer ISO/IEC - International Organization for Standardization and International Electrotechnical Commission JSON - JavaScript Object Notation JSP - Java Server Pages MIME - Multipurpose Internet Mail Extension PDA - Personal Digital Assistant PHP - PHP: Hypertext Preprocessor SAX - Simple API for XML SGML - Standard Generalized Markup Language URL - Unique Resource Locator UTF-8 - Unicode Transformation Format-8 XHR - XMLHttpRequest XHTML - Extensible HyperText Markup Language XML - Extensible Markup Language XSLT - Extensible Stylesheet Language Transformations W3C - World Wide Web Consortium 8 Lista de Figuras FIGURA 1 – Exemplo de transação HTTP .................................................................... 15 FIGURA 2 – Transação HTTP com processamento do lado servidor ........................... 16 FIGURA 3 – Servidor envia ao cliente documento HTML contendo JavaScript ............ 16 FIGURA 4 – Modelo de funcionamento de uma aplicação web atual ............................ 17 FIGURA 5 – Modelo tradicional e modelo Ajax de aplicação web ................................. 19 FIGURA 6 – Relacionamento entre as tecnologias empregadas em Ajax ..................... 21 FIGURA 7 – Hierarquia de objetos no BOM ................................................................... 39 FIGURA 8 – Janelas de diálogo confirm(), prompt() e alert() ......................................... 42 FIGURA 9 – Modelo event bubbling de fluxo de evento ................................................. 48 FIGURA 10 – Modelo DOM de fluxo de evento .............................................................. 48 FIGURA 11 – Conteúdo do arquivo mensagem.txt exibido na tela ................................ 57 FIGURA 12 – Árvore de nós representando documento XML ....................................... 66 FIGURA 13 – Relação entre as principais propriedades da interface Node ................... 68 FIGURA 14 – Aplicação realizando requisição XML ....................................................... 81 FIGURA 15 – Interface do protótipo Ajax ........................................................................ 83 FIGURA 16 – Protótipo exibindo aviso de resposta em andamento ............................... 86 FIGURA 17 – Registro habilitado para edição ................................................................ 87 FIGURA 18 – Usuário cadastrando novo registro ........................................................... 88 FIGURA 19 – Links para navegação das páginas .......................................................... 88 FIGURA 20 – Registro sendo editado após busca através da aba "Procurar" ................ 89 FIGURA 21 – Aplicação usando tema azul e exibindo a aba "Configurações" ............... 90 9 Lista de Códigos e Tabelas CÓDIGO 1 – Estrutura básica de um documento XHTML .............................................. 25 CÓDIGO 2 – Estrutura básica de um documento HTML ................................................ 27 TABELA 1 – Elementos e sua abordagem correspondente ........................................... 29 CÓDIGO 3 – Inserção de folha de estilo em documento HTML ..................................... 32 CÓDIGO 4 – Exemplo de utilização da regra @import .................................................. 32 CÓDIGO 5 – Bloco de código em JavaScript ................................................................. 36 CÓDIGO 6 – Estruturas if-else e for em JavaScript ....................................................... 36 CÓDIGO 7 – Criação e utilização de um objeto Array .................................................... 38 CÓDIGO 8 – Documento HTML usando framesets ........................................................ 40 CÓDIGO 9 – Uso do método window.open() .................................................................. 41 CÓDIGO 10 – Utilização das janelas de diálogo alert(), confirm() e prompt() ................ 42 CÓDIGO 11 – Emprego do objeto navigator para detecção do navegador em uso ....... 44 CÓDIGO 12 – Documento HTML .................................................................................... 47 CÓDIGO 13 – Atribuição de event handlers a objeto no código JavaScript ................... 49 CÓDIGO 14 – Atribuição de event handlers no Internet Explorer ................................... 49 CÓDIGO 15 – Atribuição de event handlers de acordo com o DOM .............................. 50 CÓDIGO 16 – Técnica para detecção do objeto event ................................................... 51 CÓDIGO 17 – Criação de um objeto XMLHttpRequest .................................................. 54 CÓDIGO 18 – Utilização do objeto XMLHttpRequest ..................................................... 57 CÓDIGO 19 – Documento XML representado acervo de biblioteca ............................... 60 TABELA 2 – Entidades de caractere usadas em documentos XML ............................... 62 CÓDIGO 20 – Exemplo do emprego de uma entidade de caractere .............................. 62 TABELA 3 – Suporte ao DOM pelos principais navegadores ......................................... 65 CÓDIGO 21 – Documento XML ...................................................................................... 65 CÓDIGO 22 – Tabela HTML ........................................................................................... 74 CÓDIGO 23 – Criação de tabela através do DOM HTML .............................................. 74 CÓDIGO 24 – Acesso a folha de estilo CSS através do DOM ....................................... 75 CÓDIGO 25 – Criação de documento XML em JavaScript ............................................ 77 CÓDIGO 26 – Aplicação para cadastro de nome e e-mail ............................................. 80 CÓDIGO 27 – Criação dos pares nome/valor e envio de requisição .............................. 85 CÓDIGO 28 – Documento XML contendo resposta do servidor .................................... 85 CÓDIGO 29 – Implementação da navegação pelo teclado ............................................ 87 CÓDIGO 30 – Função que implementa o recurso de mudança de tema ....................... 91 CÓDIGO 31 – Técnica para evitar armazenamento de resposta para GET .................. 91 10 1. INTRODUÇÃO Desde o início do uso dos computadores as pessoas têm aprendido a utilizá-los de maneira a compensar a falta de capacidade destes em entender os seres humanos. A situação ideal seria aquela em que bastaria dizer qual tarefa deve ser realizada para que o computador respondesse ao comando. A tecnologia, com o passar do tempo, tem evoluído sua capacidade de ser amigável ao usuário, porém ainda existe um longo caminho a ser percorrido e até que se alcance a situação ideal em que as pessoas se comuniquem com computadores como se comunicam entre si, elas precisam aprender como dizer ao computador o que querem que seja feito. Em meio a esse processo de interação homem-máquina a interface que o software provê exerce papel fundamental. O nível de satisfação do usuário está diretamente ligado à qualidade da interface de utilização do software. A indústria do software aprendeu muito neste sentido e percebeu, de acordo com Darie et al. (2006, p. 7), que “... o equivalente a um motor potente em um carro esporte vermelho é a usabilidade e acessibilidade para o software.”. Ícones, janelas, botões e menus corroboram essa constatação, já que se encontram na grande maioria dos softwares existentes no mercado direcionados ao usuário comum. Uma vez que a lucratividade dos negócios está normalmente ligada ao nível de satisfação dos clientes, tem-se buscado proporcionar ao usuário uma experiência de utilização cada vez melhor. Segundo Darie et al. (2006, p. 8), o termo usabilidade de software é definido como “... a arte de atender às necessidades dos usuários com relação à interface, entendendo a natureza de seu trabalho e desenvolvendo software de maneira adequada.”. Técnicas de usabilidade são historicamente utilizadas em aplicações desktop, por estas possuírem as ferramentas necessárias para tal. Aplicações desktop possuem interatividade e usabilidade muito melhores que aplicações web, basta utilizar um simples processador de texto ou uma planilha de cálculo para notar a quantidade de interações que ocorrem entre o usuário e a aplicação. Essa diferença se deve ao fato das aplicações web terem sido concebidas originalmente para transmitir apenas textos e imagens, não funcionalidades complexas. Além disso, aplicações web possuem problemas relativos à padronização, pois é necessário testá-las em dois ou três navegadores diferentes para se ter certeza de que vão funcionar corretamente. Porém, ainda assim cresce cada vez mais a utilização da web para fornecer serviços e recursos. O motivo desse crescimento são as vantagens tecnológicas que as aplicações web apresentam em relação às aplicações desktop: 11 − São disponibilizadas de maneira fácil e com baixo custo: um computador com navegador web e acesso à Internet ou Intranet é o suficiente para que o usuário possa utilizar uma aplicação web; − São atualizadas de maneira fácil e com baixo custo: a partir do momento em que é realizada a atualização do software localizado no servidor todos os usuários automaticamente têm acesso à nova versão; − Possuem requisitos flexíveis de utilização: uma aplicação corretamente desenvolvida pode ser utilizada através de qualquer navegador web moderno, independentemente da plataforma empregada pelo usuário; − Facilitam o armazenamento de informações de maneira centralizada: quando vários locais necessitam acessar as mesmas informações, armazená-las em um mesmo local é mais simples do que manter bases de dados em diferentes locais, minimizando problemas com sincronização de informações e diminuindo riscos de segurança. Apesar das vantagens citadas terem conferido às aplicações web grande popularidade, seu modelo de funcionamento apresenta-se como uma barreira à questão da usabilidade e satisfação do usuário. Gehtland (2006, p. 6) define a que se propunha a web inicialmente: “A web teve início mais como um repositório de documentos. [...] Seu propósito era compartilhamento de documentos e informações, sem nenhum senso significativo de interatividade.”. Asleson e Schutta (2006, p. 3) também comentam: “... cientistas usavam a Internet para trocar documentos de pesquisa, e universidades colocavam online informações de aulas. O mercado ainda não tinha descoberto o que fazer com esse novo 'canal'.”. Hoje, praticamente todo o mercado encontra-se na web e, além dos recursos e serviços disponibilizados tornarem-se cada vez mais complexos, fornecer ao usuário uma experiência de utilização agradável e satisfatória é fator primordial. Faz-se necessário romper a limitação do modelo tradicional das aplicações web e aproximá-las das aplicações desktop. Vários esforços têm sido realizados com esse objetivo e no ano de 2005 Jesse James Garret, através de seu ensaio “Ajax: A New Approach to Web Applications” (Ajax: Uma Nova Abordagem para as Aplicações Web), criou o termo Ajax (Asynchronous JavaScript + XML) definindo-o como uma maneira de se desenvolver aplicações web mais interativas, utilizando um determinado conjunto de tecnologias. A abordagem Ajax elimina a necessidade de recarregamento e bloqueio da aplicação sempre que requisições são feitas ao servidor (modelo síncrono) passando a enviar as requisições em segundo plano e atualizando apenas o que é necessário, sem bloquear a aplicação (modelo assíncrono). A proposta é sobrepor o modelo tradicional, adicionando interatividade e usabilidade às aplicações web, tornando seu funcionamento semelhante ao das aplicações desktop. A técnica tem sido adotada em vários sites na web, dentre os quais pode-se destacar o Gmail, 12 Google Suggest e Google Maps da Google e o mecanismo de busca A9 (www.a9.com) da Amazon, exemplos de grandes empresas que adotaram o método para melhorar a experiência de uso do usuário. 1.1 Objetivo Disponibilizar recursos e interatividade através da web sempre foi uma tarefa difícil, devido ao seu modelo de funcionamento. Tecnologias como Flash e Java Applets surgiram com o intuito de atender tais demandas, porém apresentam certas desvantagens (necessidade de instalação de plug-in ou máquina virtual, maior consumo de banda, requisitos maiores de hardware) que restringem seu uso. O objetivo do presente trabalho é realizar um estudo da empregabilidade da técnica Ajax como opção a ser adotada no desenvolvimento de aplicações web que apresentem melhores recursos de usabilidade, sobrepondo as limitações do modelo tradicional com a finalidade de proporcionar ao usuário uma melhor experiência de utilização. Para isso, serão analisadas as tecnologias que compõem esse método, seu modo de funcionamento, vantagens e desvantagens, além da implementação de protótipo utilizando a técnica em questão. Ao final do estudo serão apresentadas as conclusões relativas à viabilidade do método para a finalidade proposta e possíveis observações adicionais acerca de pontos fortes e desvantagens. 1.2 Estrutura do trabalho No capítulo 2 será realizado um estudo comparativo entre os modelos tradicional e o modelo Ajax de aplicações web. Características e modo de funcionamento serão analisados. Os capítulos 3, 4 e 5 terão como conteúdo um estudo das tecnologias que compõem a técnica Ajax. Inicialmente, no capítulo 3 serão abordadas as linguagens HyperText Markup Language/Extensible HyperText Markup Language (HTML/XHTML), utilizadas para definir o conteúdo e estrutura do documento web e Cascading Style Sheets (CSS), empregada para formatação visual. No capítulo 4 será abordado o JavaScript, utilizado para a programação dos eventos e fluxo da aplicação e o objeto XMLHttpRequest pertencente a esta linguagem, responsável pela tarefa de realizar a comunicação assíncrona com o servidor. Além destes, serão analisados no capítulo 5 o DOM (Document Object Model), que especifica uma interface com o conteúdo, a estrutura e o estilo do documento e o Extensible Markup Language (XML), utilizado como formato de dados para a troca de dados entre cliente e servidor. 13 No capítulo 6 será apresentado um protótipo desenvolvido utilizando a metodologia proposta, e a implementação será analisada para verificar a capacidade da técnica em atender o objetivo determinado. Ao final do estudo, no capítulo 7, serão feitas as conclusões acerca do tema, através das constatações encontradas nos capítulos anteriores. 14 2. MODELOS TRADICIONAL E AJAX DE APLICAÇÕES WEB A Internet não foi sempre como é conhecida hoje. Várias mudanças ocorreram ao longo do tempo. No início, todas as páginas web eram estáticas. Usuários solicitavam um recurso e o servidor o retornava. Para a grande maioria dos sites web, isso era o suficiente as páginas web não eram nada mais que cópias eletrônicas de textos. Com o tempo, a quantidade de pessoas conectadas à rede foi aumentando e junto com ela a demanda por experiências de utilização mais dinâmicas. Para compreender o modelo de funcionamento das aplicações web é preciso primeiramente analisar as tecnologias e abordagens desenvolvidas que fazem a web funcionar da maneira que é conhecida atualmente. Conforme explicam Darie et al. (2006) em 1991 foi criado o HyperText Transfer Protocol (HTTP), protocolo utilizado para transmitir dados pela Internet. Através deste protocolo são transmitidos páginas web, imagens e arquivos. HTTP não é o único protocolo existente na Internet para transmissão de dados, sua importância reside no fato de ser utilizado para a transmissão de conteúdo web. Quando é digitado no navegador um endereço, ou Unique Resource Locator (URL), como por exemplo www.google.com.br, automaticamente é inserido na frente deste o "http://", assumindo que será utilizado tal protocolo para acessar a página. O HTTP funciona dividido em duas partes: uma requisição e uma resposta. Quando uma URL é digitada no navegador (conhecido como cliente web), este envia uma requisição contendo o endereço digitado e algumas informações a respeito dele próprio. O servidor web recebe a requisição e envia uma resposta, contendo informações sobre a requisição e os dados existentes naquele endereço (caso exista). Após receber a resposta o navegador a interpreta, exibindo a página web. O tipo de documento padrão da web é o HyperText Markup Language (HTML), uma linguagem compreendida, processada e exibida pelos navegadores. Sua finalidade é descrever o formato e conteúdo do documento, que é composto basicamente de texto estático e imagens. O navegador, ao receber a resposta de um determinado endereço, processa esse documento HTML e o exibe. É importante salientar que o HTML não foi concebido para disponibilizar aplicações web complexas com conteúdo interativo. Quando se deseja acessar outro documento HTML, é necessário realizar novamente o processo de carregamento de toda a página, enviando a requisição e processando a resposta do servidor. A figura 1 mostra o funcionamento de uma transação quando o usuário acessa uma página web utilizando o protocolo HTTP: 15 FIGURA 1 – Exemplo de transação HTTP. A dupla HTTP/HTML é a base do funcionamento da web como a conhecemos hoje, e é clara a limitação que essa combinação apresenta em relação ao que pode ser feito permite aos usuários apenas acessar conteúdo estático (documentos HTML) através da web. Para suprir essa falta de funcionalidades, várias tecnologias têm sido desenvolvidas. Ainda que as requisições web continuem funcionando através do protocolo HTTP, duas alternativas se apresentam: pode-se criar os dados dinamicamente no servidor web, além de ser possível também que esses dados contenham mais do que apenas HTML, permitindo ao cliente executar outras funcionalidades ao invés de apenas exibir páginas estáticas. As tecnologias que fazem uso dessas alternativas e permitem a web funcionar de maneira melhorada são divididas em duas categorias: − Tecnologias server-side (ou lado-servidor): são aquelas que habilitam o servidor a utilizar lógica para construir páginas web dinamicamente; − Tecnologias client-side (ou lado-cliente): permitem ao cliente web realizar mais tarefas ao invés de apenas exibir documentos estáticos. As tecnologias server-side habilitam o servidor web a realizar outras tarefas, além de simplesmente retornar ao cliente um documento HTML solicitado, como por exemplo cálculos complexos, programação orientada a objeto e integração com bancos de dados. Alguns exemplos dessas tecnologias são CGI (Common Gateway Interface), PHP (PHP: Hypertext Preprocessor), ASP (Active Server Pages), e JSP (Java Server Pages). Darie et al. (2006) definem o processamento lado-servidor como sendo o motor que causou a revolução da web, e a razão pela qual esta é tão útil atualmente. É importante ressaltar que, independentemente do processamento realizado pelo servidor, a resposta é enviada em um formato que o cliente entenda, ou seja, normalmente HTML, que possui muitas limitações como mencionado anteriormente. A figura 2 mostra o funcionamento de uma transação em que ocorre processamento do servidor para enviar a resposta ao cliente: 16 FIGURA 2 – Transação HTTP com processamento do lado servidor. As tecnologias client-side ou lado-cliente têm a finalidade de solucionar a questão dos documentos de funcionalidade limitada enviados pelo servidor web. Pode-se citar como exemplo o Macromedia Flash, que necessita de um plug-in instalado no navegador, e os Java Applets, que utilizam uma máquina virtual pré-instalada. Ambas são tecnologias bastante populares, mas que normalmente são utilizadas apenas em determinados contextos por apresentarem certas desvantagens, como a necessidade de instalação de softwares adicionais ou maior consumo de recursos do sistema. Além destas, existe a linguagem JavaScript, principal tecnologia client-side. Quando um cliente solicita uma página web, o servidor envia o documento HTML contendo código JavaScript embutido, que é interpretado e processado nativamente pelos navegadores modernos, adicionando grandes funcionalidades às páginas web, como por exemplo verificações de formulários com avisos para evitar erros de digitação e a necessidade de reiniciar o processo de preenchimento. A figura 3 exibe o funcionamento de uma transação em que o servidor realiza o processamento e envia ao cliente um documento HTML contendo JavaScript: FIGURA 3 – Servidor envia ao cliente documento HTML contendo JavaScript. O par HTTP/HTML, juntamente com as tecnologias server-side e client-side definem o modelo atual de funcionamento das aplicações web. 17 2.1 Modelo tradicional de aplicações web A partir da análise feita, é possível definir uma seqüência de passos que caracterizam o modelo de funcionamento das aplicações web: 1. o usuário digita o endereço (ou URL) na barra de endereços do navegador; 2. o navegador (ou cliente web) envia uma requisição HTTP ao servidor, contendo o endereço digitado e informações referentes ao próprio cliente web; 3. o servidor cria a resposta, esta contendo informações da requisição e dados (podendo ou não para isso realizar algum tipo de processamento com tecnologia server-side), e envia a resposta HTTP com o documento HTML (provavelmente contendo código JavaScript embutido) para o cliente; 4. o cliente recebe a resposta e processa o documento recebido, exibindo os dados contidos nas instruções HTML e adicionando as funcionalidades de acordo com o código JavaScript; 5. o usuário realiza uma ação que necessita de dados do servidor, e o processo se reinicia a partir do passo 2. A figura 4 exemplifica o funcionamento das aplicações web atuais: FIGURA 4 – Modelo de funcionamento de uma aplicação web atual. Das primeiras páginas web que exibiam praticamente apenas textos até o modelo atual, muitas mudanças aconteceram. O servidor pode gerar os dados dinamicamente, comunicar-se com bancos de dados, além do cliente ser capaz de processar outras funcionalidades ao invés de simplesmente exibir conteúdo HTML. Porém uma característica permanece inalterada: o paradigma requisição/resposta. De acordo com Darie et al. (2006), cada vez que o cliente precisa de novos dados do servidor uma nova requisição HTTP precisa ser feita para recarregar a página, congelando a atividade do usuário. Ou seja, sempre que o usuário executa alguma ação em que é preciso recuperar novos dados do servidor, mesmo sendo uma ação simples, é necessário submeter uma requisição e a aplicação fica bloqueada até que uma resposta seja recebida e processada, ocorrendo 18 então uma atualização completa da página. Durante este processo o usuário não tem alternativa a não ser esperar, e esperar sempre que uma interação ocorre, diminuindo muito o nível de usabilidade da aplicação. Tal característica é um fator limitador à qualidade da experiência de utilização do usuário. Como será visto a seguir, o modelo Ajax busca solucionar a limitação relacionada a esse paradigma. 2.2 Modelo Ajax de aplicações web Ajax não é uma nova tecnologia, mas sim uma técnica para desenvolvimento de aplicações web. Isso significa que neste novo modelo de funcionamento não há a adoção de novas tecnologias, mas na verdade a utilização de um novo conceito. Zakas et al. (2006, p. 11) definem: "Ao invés do modelo tradicional de aplicações web no qual o próprio navegador é responsável por iniciar as requisições para e processar as respostas do servidor web, o modelo Ajax provê uma camada intermediária - chamada por Garret de motor Ajax - para controlar essa comunicação.". Garret (2005) explica o funcionamento do motor Ajax: "Ao invés de carregar uma página web no começo da sessão, o navegador carrega um motor Ajax [...] esse motor é responsável tanto por desenhar a interface que o usuário vê, quanto realizar a comunicação com o servidor representando o usuário.". Neste modelo, o servidor - que tradicionalmente envia ao cliente documentos HTML passa a enviar dados que o motor Ajax pode utilizar, podendo ser texto puro, código XML, HTML, ou outro formato de dados necessário. O importante neste caso é que o motor Ajax seja capaz de interpretar e processar as informações. Por sua vez, o motor Ajax ao receber a resposta do servidor, processa e realiza alterações na interface do usuário1 de acordo com os dados recebidos. Devido ao fato do processo envolver transferência de uma quantidade menor de informações do que em uma aplicação web tradicional (não é necessário recarregar uma página inteira) as atualizações na interface do usuário são mais rápidas, e este é capaz de fazer seu trabalho de maneira mais ágil. A figura 5 mostra a comparação entre a estrutura dos modelos tradicional e Ajax: 1 Normalmente utilizando o DOM para acessar os elementos da interface, como será visto mais adiante. 19 FIGURA 5 – Modelo tradicional e modelo Ajax de aplicação web. O funcionamento de uma aplicação Ajax segue a seguinte seqüência de passos: 1. o usuário digita o endereço (ou URL) na barra de endereços do navegador; 2. o navegador (ou cliente web) envia uma requisição HTTP ao servidor, contendo o endereço digitado e informações referentes ao próprio cliente web; 3. o servidor cria a resposta, esta contendo informações da requisição e dados (podendo ou não para isso realizar algum tipo de processamento com tecnologia server-side), e envia a resposta HTTP com o documento HTML contendo o motor Ajax embutido, codificado em JavaScript; 4. o cliente recebe a resposta e processa o documento recebido, exibindo os dados contidos nas instruções HTML e habilitando o motor Ajax; 5. o usuário realiza uma ação que é recebida pelo motor Ajax. Se não há necessidade de buscar dados no servidor, o motor faz as alterações necessárias na interface em resposta à ação disparada. Caso contrário é feita uma requisição em segundo plano ao servidor, sem bloquear a utilização da aplicação pelo usuário; 6. o servidor responde à requisição, enviando os dados (normalmente em XML) necessários ao processamento do motor Ajax; 7. O motor realiza as atualizações na interface do usuário, de acordo com os dados recebidos na resposta. Analisando a seqüência de passos nota-se as vantagens desse modelo de funcionamento: é possível comunicar-se com o servidor de maneira assíncrona, de forma que enquanto o motor Ajax faz a requisição ao servidor, o usuário possa interagir com a aplicação, sem precisar aguardar pelo processamento da resposta. Elimina-se o problema 20 presente no modelo clássico no qual o fluxo de trabalho do usuário é interrompido sempre que este realiza uma ação, obrigando-o a aguardar o desbloqueio da aplicação enquanto a resposta do servidor não é processada. Em certos casos, o próprio motor Ajax pode responder à ação do usuário, sem a necessidade de realizar uma requisição ao servidor1. Tal característica, aliada ao fato das respostas do servidor possuírem apenas os dados necessários ao processamento do motor Ajax ao invés de uma página inteira a ser processada pelo navegador, tornam também as aplicações muito mais ágeis. Ajax faz uso de uma técnica conhecida como remote scripting, que permite ao cliente realizar requisições ao servidor de forma assíncrona, ou seja, o cliente pode trocar informações com o servidor sem a necessidade de bloquear a utilização da aplicação pelo usuário durante o processo. Apesar do termo Ajax ser recente, remote scripting não é. Uma das mais conhecidas, a técnica hidden IFRAME (IFRAME escondido) implementa remote scripting e já existe há vários anos. Tal técnica consiste em utilizar uma tag IFRAME invisível ao usuário em um documento HTML, através da qual é feita a troca de dados com o servidor. Apesar da tag não ser destinada para esse fim e tratar-se na verdade de uma adaptação, sua adoção é comum. Além do remote scripting, as tecnologias associadas ao termo Ajax também não são recentes. Na realidade, a tecnologia mais recente - o objeto XMLHttpRequest (XHR), responsável justamente pela comunicação assíncrona com o servidor - existe desde a versão 5 do navegador Internet Explorer (IE), lançado em março de 1999. O fato recente neste cenário é o nível de suporte dos navegadores em relação ao objeto XHR. Segundo Asleson e Schutta (2006, p. 13), “Originalmente, o objeto XHR era suportado apenas pelo Internet Explorer (portanto limitando o seu uso), porém começando com Mozilla 1.0 e Safari 1.2 o suporte difundiu-se.”. Neste ponto, com a proliferação de aplicações como Google Maps, Google Suggest, Gmail, Flickr, Netflix e A9, XHR torna-se padrão de fato e a metodologia Ajax popularizou-se. 2.3 Tecnologias As principais tecnologias que compõem o modelo Ajax são as seguintes: – HTML/XHTML: definição e estruturação do conteúdo a ser exibido ao usuário; − CSS: definição de estilos visuais, a serem utilizados para formatar a exibição do conteúdo HTML/XHTML; − JavaScript: linguagem de programação que fornece acesso às funcionalidades do navegador, é utilizada para codificar a aplicação Ajax; 1 Isso já ocorre com as aplicações web tradicionais, porém usualmente de maneira superficial, como verificações de preenchimento de formulários. Com Ajax, essa possibilidade é mais explorada. 21 − XMLHttpRequest: objeto JavaScript usado para a troca de dados entre o cliente e o servidor, realizando a comunicação em segundo plano; − DOM: interface contendo os elementos da página web que podem ser manipulados através de JavaScript, permitindo à aplicação Ajax alterar a interface do usuário, redesenhando partes da página; − XML: formato de representação de dados utilizado para a troca de informações entre cliente e servidor. Através da estrutura exibida na figura 6 é possível observar a relação entre as tecnologias dentro deste modelo: FIGURA 6 – Relacionamento entre as tecnologias empregadas em Ajax. Outras tecnologias também podem ser utilizadas em implementações Ajax, como Extensible Stylesheet Language Transformations (XSLT), cuja função é transformar um documento XML em outro diferente (dentro da abordagem Ajax, normalmente um documento XHTML). Além disso, a utilização de XML como formato para a troca de dados entre cliente e servidor não é obrigatória, pois pode-se utilizar qualquer formato baseado em 22 texto, sendo possível encontrar casos em que é usado JavaScript Object Notation (JSON) ou mesmo HTML. Porém, tais implementações não fazem parte do padrão adotado e normalmente são usadas em determinados contextos, de maneira que estão fora de escopo e não serão abordadas neste estudo. Pode-se notar que as tecnologias empregadas no modelo tradicional continuam presentes no modelo Ajax: a comunicação entre cliente e servidor ainda é feita através do protocolo HTTP; HTML continua sendo utilizado para exibir as informações ao usuário; o servidor continua gerando conteúdo dinamicamente através das tecnologias server-side e JavaScript continua sendo utilizado do lado cliente. A diferença está na abordagem: o servidor passa a entregar dados, e não documentos HTML completos; JavaScript passa a ser utilizado para criar o motor Ajax, que por sua vez assume as funções de requisitar informações ao servidor e desenhar a interface exibida ao usuário. Esse é um ponto forte da técnica Ajax: mantém as características das aplicações web que as tornaram populares, além de não ser necessário aos programadores aprenderem uma nova tecnologia serverside, pois Ajax pode interagir com qualquer uma delas. Nos próximos capítulos, será feita uma análise das tecnologias citadas que fazem parte da metodologia de desenvolvimento Ajax. 23 3. HTML/XHTML E CSS O início da Internet ocorreu no final dos anos sessenta com o intuito de se criar uma robusta rede de computadores, capaz de lidar com a perda de vários pontos, mantendo a comunicação entre os restantes. Os fundos para criação de tal rede vieram do Departamento de Defesa americano, que tinha um grande interesse em construir uma rede de informação que pudessem suportar um ataque nuclear. Kennedy e Musciano (2006) explicam que a rede resultante foi um grande sucesso técnico, porém era limitada em tamanho e escopo. Em sua maior parte, apenas instituições de defesa e instituições acadêmicas podiam obter acesso ao que na época era conhecida como Advanced Reserch Projects Agency Network of the Departament of Defense (ARPAnet). No início dos anos 90, empresas e indivíduos, ávidos por aproveitar a facilidade e o poder das comunicações digitais globais, pressionaram as maiores redes de computadores, principalmente as de Internet baseada em fundos do governo americano, para que liberassem seus sistemas para um tráfego praticamente irrestrito. A maior parte das informações disponíveis na rede eram simples textos sobre assuntos acadêmicos. A Internet era muito desorganizada e, fora do meio governamental e acadêmico, poucas pessoas tinham o conhecimento ou interesse para aprender como usar os misteriosos softwares ou para gastar seu tempo pesquisando minuciosamente através de documentos procurando os de seu interesse. No mesmo período em que a Internet foi aberta para o mercado tal situação mudou, quando cientistas do Conseil Européen pour la Recherche Nucléaire (CERN, ou Organização Européia para a Pesquisa Nuclear) lançaram uma linguagem de criação de apresentações e um sistema de distribuição que eles haviam construído para criação e compartilhamento, através da Internet, de documentos eletrônicos integrados com capacidades multimídia. De acordo Kennedy e Musciano (2006) dessa maneira nasceram o HTML, o software navegador, e a web. Os autores não precisariam mais distribuir seus trabalhos em coleções fragmentadas de imagens, sons e texto. O HTML unificou esses elementos. Além disso, a web permitiu a ligação de hipertexto, através da qual documentos referenciavam automaticamente outros documentos localizados em qualquer lugar do mundo, gerando uma mídia totalmente nova, de troca de informações e comércio em âmbito global. 24 3.1 O que são HTML e XHTML HTML e XHTML definem a sintaxe e localização de instruções especiais que não são exibidas pelo navegador, mas o dizem como exibir o conteúdo do documento, sendo este conteúdo texto, imagens, e outras mídias suportadas. Eles também tornam um documento interativo através de ligações de hipertexto especiais (hyperlinks), que conectam o documento a outros em qualquer lugar, assim como também a recursos da Internet. HTML é baseado na metalinguagem Standard Generalized Markup Language (SGML), e sua versão atual, HTML 4.01, não é conforme com o formato XML. A evolução do HTML é o XHTML, uma linguagem conforme com XML que procura suportar o conjunto de características do HTML 4.01, atendendo às regras mais rígidas do XML. Mesmo que XHTML tenha as características do HTML, ambas as linguagens possuem certas diferenças, que serão abordadas em um segundo momento. Segundo Griffiths (2007) HTML/XHTML possui uma sintaxe direta, sendo seu conteúdo estruturado em elementos que, de acordo com Haine (2006), contêm normalmente uma tag de abertura, atributos opcionais, conteúdo, e uma tag de fechamento. Uma tag é indicada pelo sinal de menor (<) e o sinal de maior (>), como pode ser visto no seguinte exemplo: <a href="http://www.google.com.br">Busca do Google</a> Sendo: – “<a href=”http://www.google.com.br“>”: é a tag de abertura, que define o início do elemento; – “</a>”: tag de fechamento, indica o final do elemento; – “href”: atributo do elemento; – “http://www.google.com.br”: valor do atributo; – “Busca do Google”: conteúdo do elemento; – “<a href=”http://www.google.com.br“>Busca do Google</a>”: o elemento completo. Nem todos os elementos possuem uma tag de fechamento, como por exemplo <br>, <meta> e <img>. Conhecidas como self-closing tags (tags de autofechamento), seu conteúdo e formatação são gerenciados através dos valores de seus atributos. Esse tipo de elemento denota uma das diferenças entre HTML e XHTML: enquanto que em HTML são escritos simplesmente como <br> ou <meta>, em XHTML deve-se adicionar uma barra, na forma <br /> e <meta />. Neste ponto, cabe descrever as principais características que diferenciam XHTML do HTML, de acordo com Haine (2006): – As tags <html>, <head> e <body> são mandatórias em XHTML. 25 – A tag <html> deve ter um atributo “xmlns” com o valor de “http://www.w3.org/1999/ xhtml”. – Todos os elementos precisam ser fechados. Uma tag de abertura precisa ter outra igual de fechamento ou, no caso de uma tag self-closing, ter uma barra, como já dito anteriormente. – Todas as tags devem ser escritas em letras minúsculas. – Todos os valores de atributos devem ser referenciados utilizando aspas simples ou duplas. Ou seja, class=page está incorreto, enquanto que class=’page’ ou class=”page” estão corretos. – Todos os atributos devem possuir valores. Alguns atributos, em HTML, podem ser escritos em uma forma curta, como em <option selected>data</option>. Porém em XHTML deve-se escrever <option selected=”selected”>data</option>. – O símbolo & deve ser codificado. Deve-se escrever & ao invés de simplesmente &. Tais pontos mostram a natureza mais exigente do documento XHTML em relação ao HTML, para atender aos padrões XML. Existem outras características que diferenciam ambos, porém não serão abordadas por estarem fora do escopo deste trabalho. Foram apresentadas as principais diferenças para que seja levado em consideração o fato de que mesmo sendo HTML e XHTML muito semelhantes, o desenvolvedor deve estar atento às diferenças ao fazer sua escolha. Além disso, é importante salientar que ambas podem ser utilizadas no modelo Ajax indistintamente. A estrutura básica de um documento XHTML segundo Haine (2006) é a exibida no código 1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>O título</title> </head> <body> <p>O conteúdo</p> </body> </html> CÓDIGO 1 – Estrutura básica de um documento XHTML. As duas primeiras linhas do documento contêm uma declaração de doctype. Essa declaração provê uma indicação de qual Document Type Definition (DTD) será utilizado. Como explicam Asleson e Schutta (2006) a maioria dos navegadores funciona possuindo 26 dois modos de renderização: strict ou standards mode e quirks mode. Navegadores web usam strict mode quando o doctype indica que a página web é escrita para seguir uma determinada recomendação World Wide Web Consortium (W3C1) como HTML 4.01 ou XHTML 1.0, e usam quirks mode quando um doctype não está disponível ou quando a página contém conflitos com o doctype especificado. De acordo com a W3C (2007B), isso significa que diferentes regras são aplicadas para a apresentação do documento, estando o standards mode em conformidade com os padrões W3C e o quirks mode baseado em comportamento não-padrão, de navegadores antigos. Ainda de acordo com York (2005), quirks mode existe como uma maneira de se prover retro-compatibilidade com várias páginas web que foram criadas antes que os padrões W3C fossem implementados e passassem a ser amplamente utilizados, ou para aquelas as quais o autor ainda não tem conhecimento dos padrões. A declaração de doctype não segue nenhuma das regras de sintaxe para criação de tags HTML, devendo ser escrita exatamente como exibida. Além do XHTML 1.0 Strict exibido no código, existem doctypes XHTML 1.0 Transitional e Frameset, HTML 4.01 Strict, HTML 4.01 Transitional e HTML 4.01 Frameset, além de outras versões de HTML2. Basicamente, os doctypes Transitional possuem tags e atributos que foram desaprovados no doctype Strict (são doctypes de transição, como o próprio nome diz), enquanto que os doctypes Frameset são adotados em páginas que utilizam frames. A questão relativa à utilização de doctypes é importante na criação de aplicações Ajax, pois o desenvolvedor que utiliza os padrões W3C não só evita inconsistências na interpretação de código CSS e torna suas aplicações acessíveis por todos os navegadores web modernos, como também facilita seu trabalho ao garantir que o navegador possa criar uma representação acurada do DOM a partir do código HTML. Segundo Asleson e Schutta (2006), o navegador pode não ser capaz de criar uma representação correta do DOM se a página foi mal escrita, forçando o navegador a renderizá-la utilizando quirks mode. Uma representação incorreta do DOM pode tornar difícil o acesso e a modificação do mesmo por meio do JavaScript (DOM e Javascript serão abordados mais adiante neste estudo), principalmente de uma maneira compatível com navegadores diferentes. Em seguida à declaração de doctype, na terceira linha, encontra-se uma tag de abertura <html> com um atributo xmlns. Esse atributo é usado para declarar um XML namespace, que descreve qual linguagem de marcação está sendo utilizada. O valor inserido é http://www.w3.org/1999/xhtml e deve estar presente em qualquer documento XHTML. Após o elemento <html> aberto existe, na quarta linha, o elemento <head> do documento, que contém um elemento <title> (na quinta linha) e pode conter também os elementos <style>, <script>, <meta>, e <link>. Apenas o elemento <title> é obrigatório, 1 2 Para uma abordagem mais detalhada sobre a W3C consulte o item 3.2 Web Standards. Uma relação com os DTDs disponíveis pode ser encontrada em http://www.w3.org/QA/2002/04/valid-dtd-list. 27 sendo seu conteúdo exibido na barra de título do navegador. Segundo Griffiths (2007), <style> é usado para definir código CSS específico da página, e <script> para também definir scripts específicos, como JavaScript. O elemento <link> define uma ligação com um recurso externo, como um arquivo CSS, ou um ícone. Analisando novamente a estrutura do documento XHTML, seguindo a tag de fechamento do elemento <head>, na sexta linha, há a tag de abertura do elemento <body>, na linha seguinte. Essa tag contém os parágrafos, listas, imagens e outros conteúdos, como pode ser observado o elemento de parágrafo (tag <p>) localizado na oitava linha do código. Em seguida à tag de fechamento de <body> está a tag de fechamento do elemento <html>, na décima e última linha, encerrando o documento. Alguns documentos XHTML podem também apresentar uma declaração XML no seguinte formato: <?xml version="1.0" encoding="iso-8859-1"?> Essa linha é inserida antes da declaração de doctype, e seu objetivo é declarar que o documento em questão é um documento XML, sua versão, e o character set (conjunto de caracteres) em que o documento foi codificado. De acordo com Haine (2006) tal declaração é opcional, e utilizá-la pode causar efeitos adversos, sendo o pior deles fazer o navegador Internet Explorer passar a funcionar em quirks mode - qualquer coisa que apareça antes da declaração de doctype, exceto espaço em branco, gera esse efeito. Assim, o autor sugere que essa linha não seja inserida. A definição do character set de um documento é um ponto relevante, pois permite que este seja exibido corretamente (evitando a exibição de caracteres incorretos). Segundo Jacobs (2006), pode-se definir o character set de várias maneiras, como uma declaração XML (como visto acima) ou utilizando uma tag <meta> dentro da seção <head>, na forma: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> para especificar o charset UTF-8, por exemplo. Porém, a maneira mais confiável de se definir o character set de um documento XHTML é fazê-lo através do cabeçalho HTTP que o servidor envia ao cliente, podendo ser realizado através da utilização de alguma tecnologia server-side ou mesmo configurando o servidor web adequadamente. A estrutura básica de um documento HTML segue o mesmo modelo do XHTML, com poucas diferenças como pode ser visto no código 2: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <title>O título</title> <p>O conteúdo</p> CÓDIGO 2 – Estrutura básica de um documento HTML. 28 Os elementos <html>, <head> e <body> não são obrigatórios em HTML, mas deve-se estar atento para o fato de que mesmo não tendo sido explicitamente criados, tais elementos existirão no DOM. Além disso, caso seja especificado algum elemento pertencente a <head> como <link> ou <meta>, ele deve aparecer antes de qualquer marcação pertencente ao elemento <body>, caso contrário a marcação será considerada inválida. 3.2 Web Standards De acordo com a definição de Griffiths (2007) web standards (ou padrões web) são regras universais que determinam como algo deve ser usado, independentemente de qualquer outra coisa (como um navegador específico, por exemplo). A utilização de web standards ajuda a garantir a compatibilidade universal e a acessibilidade. Esses padrões são criações da W3C, uma entidade independente que conta com empresas como Google, Intel, AOL, Apple, várias universidades, Sony, Microsoft, e muitos outros. A W3C (2007A) é um consórcio internacional cujo objetivo é, de acordo com a definição encontrada em seu próprio site “Levar a World Wide Web a atingir todo seu potencial através do desenvolvimento de protocolos e diretrizes que assegurem o crescimento da web em longo prazo”. A entidade busca atingir seus objetivos com a criação de padrões web e diretrizes, divulgando as chamadas Recomendações W3C. Além do próprio HTML/XHTML, a W3C é responsável por padronizar uma grande gama de tecnologias relacionadas à web como XML, CSS, HTTP e DOM, por exemplo. Os padrões HTML são baseados em semântica. Isso consiste em um processo de utilização de tags para aplicar significado, como em "esse pedaço de texto é um parágrafo" ou "o HTML neste elemento faz uma tabela". Tal processo é parte de uma importante definição: HTML deve ser utilizado para conteúdo, enquanto CSS deve ser usado para apresentação. A filosofia central dos web standards é "separação de conteúdo e apresentação". Griffiths (2007, p. XIX) afirma que: "Se você aplicar essa regra ao construir páginas web então você já está na metade do caminho em direção à realização dos web standards e dos benefícios que eles trazem". Isso significa que HTML é para uma coisa e CSS é para outra. A tabela 1 exemplifica alguns elementos e sua abordagem correspondente: 29 TABELA 1 – Elementos e sua abordagem correspondente. Os benefícios mais importantes da utilização dos web standards são: – Compatibilidade entre navegadores: um problema comum no processo de criação web foi a "necessidade" de desenvolver uma página para um navegador e outra página para outro. Mesmo hoje, alguns sites são feitos para funcionar apenas no Microsoft Internet Explorer, excluindo uma pequena, mas significante, percentagem de usuários. Porém, com exceção de algumas pequenas discrepâncias, seguir os web standards garantirá que as páginas funcionem em qualquer lugar; – Compatibilidade à frente: graças à crescente predisposição à compatibilidade, páginas web funcionarão mais como desejado em navegadores futuros do que se dependessem dos elementos proprietários não padronizados dos navegadores atuais; – Controle centralizado da apresentação: seguir web standards e utilizar CSS permite que um único ou múltiplos arquivos globais apliquem apresentação a todas as páginas web de um site. Separando dessa forma a apresentação do HTML tornamse muito mais fáceis e rápidas alterações de apresentação de todo um site, resultando em um design mais consistente; – Páginas mais leves: páginas mais leves significam diminuição de consumo de banda (reduzindo custos de hospedagem) e tempo de carregamento da página (melhora a usabilidade); – Acessibilidade: uma grande proporção de problemas de acessibilidade da web são problemas técnicos e podem ser resolvidos fazendo uso de bons padrões de HTML e CSS. Dois benefícios destacam-se entre os demais: as páginas mais leves, que provêm maior usabilidade, e a acessibilidade melhorada através do HTML e CSS. Ambas são as finalidades ao se desenvolver aplicações Ajax, o que demonstra uma grande contribuição dos web standards a esta abordagem. 30 Um princípio fundamental por trás dos web standards é que eles são independentes de navegador. Não deve ser necessário criar código específico para navegadores - se os navegadores seguirem os padrões W3C uma página deve ser o suficiente. Porém, no mundo real, os navegadores não são perfeitos. De acordo com Griffiths (2007) isso não significa que os padrões web são inúteis em termos práticos. A maioria dos navegadores populares modernos suporta a vasta maioria dos padrões web. Porém, de longe o navegador mais popular é o Internet Explorer para Windows, que possui deficiências em relação aos padrões web. Navegadores mais modernos, como Firefox e Safari, são tecnicamente superiores, mas infelizmente para o desenvolvedor poucos são os usuários que usam outra coisa além do navegador pré-instalado em sua máquina. Isso significa predominantemente Windows e Internet Explorer. Em termos gerais, não há absolutamente um motivo prático para não adotar os web standards - todos os navegadores modernos são mais que capazes de lidar com eles. O ponto a ser considerado é que ao trabalhar em um mundo multi-navegador, sempre é possível encontrar discrepâncias entre eles. Desde que sejam realizados testes em vários navegadores para garantir o funcionamento da página, questões de compatibilidade não devem causar muitos problemas. 3.3 Cascading Style Sheets (CSS) Cascading Style Sheets (Folhas de Estilo em Cascata) é uma linguagem cujo objetivo é simplificar o processo de tornar as páginas web apresentáveis. De maneira simples, CSS lida com a parte de look and feel (ou aparência) de uma página web. Quando combinado com uma linguagem estrutural de marcação como HTML, XHTML ou XML, CSS provê aos navegadores as informações que os permitem apresentar todos os aspectos visuais de um documento web. Cascading Style Sheets aplica bordas, espaços entre parágrafos, cabeçalhos ou imagens, controle de tipos ou cores de fontes, cores de segundo plano e imagens, efeitos textuais como textos sublinhados ou sobre-tachados, disposição de camadas, posicionamento, e outros efeitos de apresentação. CSS controla os aspectos de apresentação do desenho de uma página web, ao passo que HTML, XHTML ou XML controlam sua estrutura. Griffiths (2007) explica que, embora intrinsicamente ligado com o HTML na formação da página web, CSS possui uma sintaxe completamente diferente, que consiste em uma coleção de regras que são feitas de seletores, propriedades, e valores. Uma típica regra CSS é a seguinte: h1 { font-size: 2pt; } 31 Na qual: – "h1" é o seletor, que define em qual parte do HTML o CSS se aplica; – "font-size" é a propriedade, que define qual aspecto de apresentação específico do elemento alvo será ajustado; – "2pt" é um valor, que define qual o ajuste da propriedade; – "font-size: 2pt;" é conhecido como declaração; – "h1 { font-size: 2pt; }" todos juntos são definidos como sendo uma regra. Seletores especificam a quais elementos HTML as declarações de estilo devem ser aplicadas. Existem três principais tipos de seletores: seletores HTML, seletores identificadores, e seletores de classe. Seletores HTML simplesmente especificam um elemento HTML ao qual as declarações devem ser aplicadas. A declaração "h2 { color: red; }" faz com que todos os elementos h2 sejam vermelhos. Seletores identificadores anexam estilos ao elemento HTML com o id correspondente. Se existe o código HTML <h3 id="carro">Carro</h3>, para aplicar um estilo apenas para esse elemento, deve-se fazer (destaque para o caractere # no início do seletor): #carro { color: red; } Seletores de classe anexam estilos para elementos HTML que sejam da classe correspondente. Por exemplo, se existe o HTML <h3 class="veiculo">Carro</h3> e desejase aplicar estilos a esse elemento e a todos os outros da classe veiculo, a regra deve ser (destaque para o ponto no início do seletor): .veiculo { color: red; } Pode-se também anexar mais de uma classe a um elemento HTML, separando-as por espaço, como em <h3 class="veiculo utilitario">Carro</h3>. Neste caso, as duas regras seguintes seriam aplicadas: .veiculo { color: red; } .utilitario { font-style: italic; } Também é possível ser mais específico sobre quais elementos uma classe se aplica, colocando o seletor dessa classe logo após outro seletor. Para associar estilos a um elemento h2 com a classe "veiculo", por exemplo, utiliza-se o seletor h2.veiculo. Pode-se então utilizar o seletor p.veiculo para aplicar estilos específicos aos elementos p com a classe "veiculo", e assim por diante. Ainda é possível aplicar um mesmo bloco de declaração a mais de um seletor, basta separá-los por vírgula, como em: h2, #carro, .veiculo { color: red; } 32 Para que o CSS possa ser utilizado, ele deve ser anexado a um documento. Segundo York (2005) o CSS é bastante flexível com relação à maneira pela qual isso pode ser feito. Primeiramente, é possível realizar essa tarefa incluindo folhas de estilo embutidas: neste caso utiliza-se a tag <style> para inserir folhas de estilo embutidas diretamente no documento, como pode ser visto no código 3: <style type='text/css'> <!-body, td { color: blue; } --> </style> CÓDIGO 3 – Inserção de folha de estilo em documento HTML. O objetivo das linhas de comentário <!-- e --> é fazer com que navegadores antigos que não suportam CSS ignorem o texto entre elas, permitindo que o CSS fique escondido desses navegadores. Para que a tag <style> esteja de acordo com a sintaxe XHTML, é necessário o atributo type, cuja finalidade é dizer ao navegador qual é o tipo da sintaxe que se segue. O método recomendado de inclusão de CSS em um documento é fazendo uma ligação a folhas de estilo externas. A recomendação W3C permite que folhas de estilo externas sejam incluídas no documento através do uso do elemento <link> ou a partir de uma folha de estilo no próprio documento utilizando a regra @import. Um elemento <link> tem o seguinte formato: <link rel="stylesheet" href="caminho/para/css_doc.css" type="text/css" /> O atributo rel define a relação entre o documento externo e o documento solicitante. Neste caso, a relação é que o documento externo é uma folha de estilo para o documento solicitante. O atributo href é a referência de hyperlink, o caminho de onde o documento externo se encontra. Por fim, o atributo type define o tipo Multipurpose Internet Mail Extension (MIME1) do arquivo externo. A outra maneira de realizar uma ligação a uma folha de estilo externa é através da regra @import, de acordo com o código 4: <style type="text/css"> @import url(caminho/para/css_doc.css); </style> CÓDIGO 4 – Exemplo de utilização da regra @import. 1 "Um MIME type diz ao navegador qual é o tipo de mídia de um arquivo e assim o que fazer com ele." Griffiths (2007, p. 11). 33 Este método é bastante direto, colocando em frente à regra @import o url(), e entre os parênteses deste o caminho de onde o arquivo com as folhas de estilo se encontra. Ainda é possível aplicar CSS inline, utilizando o atributo style diretamente no documento HTML, como em <p style="color: red;">Não coma laranjas.</p>. Griffiths (2007) explica que essa maneira de se aplicar CSS é geralmente desencorajada e que ela perde muitos dos grandes benefícios pelos quais CSS é famoso - especialmente a separação entre apresentação e estrutura e a habilidade de realizar alterações globais a partir de uma única fonte. A utilização de Cascading Style Sheets pode reduzir a quantidade de banda necessária para transmitir um site do servidor para o navegador. De acordo com York (2005), CSS apresenta as seguintes vantagens: – A apresentação de um website inteiro pode ser centralizada em um ou poucos documentos, permitindo que sua aparência seja atualizada rapidamente; – Usuários de um website podem criar suas próprias folhas de estilo, uma característica que torna os websites mais acessíveis. Por exemplo, um usuário pode criar uma folha de estilo de alto contraste que torne o conteúdo mais fácil de ser lido; – Navegadores estão começando a suportar múltiplas folhas de estilo, característica que permite a exibição de mais de uma aparência do website ao mesmo tempo. O usuário pode simplesmente selecionar a aparência que mais lhe agrade; – Folhas de estilo permitem que o conteúdo seja otimizado para mais de um tipo de dispositivo. Utilizando o mesmo documento HTML, diferentes versões de um website podem ser apresentadas por exemplo para dispositivos como Personal Digital Assistants (PDAs) e telefones celulares; – O download é muito mais rápido porque documentos web usando CSS ocupam menos espaço em disco e consomem menos banda. As vantagens citadas demonstram claramente a contribuição que os Cascading Style Sheets dão à usabilidade de uma aplicação web e conseqüentemente à abordagem Ajax. Uma característica importante do Ajax em relação ao CSS é que as regras das folhas de estilo (e por extensão a aparência do documento) podem ser alteradas dinamicamente, tornando a usabilidade das aplicações web ainda maior. Essas alterações dinâmicas são feitas utilizando código JavaScript que é incorporado ao documento HTML. A linguagem JavaScript é a tecnologia a ser abordada no capítulo seguinte. 34 4. JAVASCRIPT JavaScript foi desenvolvido como uma linguagem de scripting leve e de propósito geral, adequada para o uso em diferentes contextos. Inicialmente nomeada LiveScript, segundo Goodman (2001) a linguagem servia para dois propósitos. Um desses propósitos era uma linguagem que administradores de servidores web pudessem usar para gerenciar o servidor e conectar suas páginas com outros serviços, como banco de dados em backend. No lado cliente - em documentos HTML - autores poderiam empregar scripts escritos nessa nova linguagem para melhorar páginas web de diferentes maneiras. Por exemplo, um autor poderia usar LiveScript para ter certeza que a informação inserida pelo usuário em um formulário está correta. Ao invés de forçar o servidor ou o banco de dados a fazer a validação (necessitando de trocas de informações entre o navegador cliente e o servidor), o computador do usuário realizaria o trabalho. Em 1995, a linguagem foi renomeada para JavaScript e lançada junto com o navegador Netscape Navigator 2.0. Ao contrário do que se possa pensar, JavaScript não tem relação com a linguagem Java, tendo recebido esse nome apenas por questões de marketing. Como explica Zakas (2005, p. 2), devido à necessidade de padronização, em 1997 o JavaScript 1.1 foi submetido como proposta ao European Computer Manufacturers Association (ECMA). "O comitê técnico 39 foi designado para 'padronizar a sintaxe e semântica de uma linguagem de scripting de propósito geral, multiplataforma e neutra de fornecedor' (http://www.ecma-international.org/memento/TC39.htm).". Foi então criado o padrão ECMA-262, definindo uma nova linguagem de scripting chamada ECMAScript. No ano seguinte, a International Organization for Standardization and International Electrotechnical Commission (ISO/IEC) também adotou ECMAScript como um padrão. Desde então, navegadores web têm procurado utilizar ECMAScript como uma base para suas implementações de JavaScript. Embora ECMAScript seja um importante padrão, não é a única parte do JavaScript. Uma completa implementação de JavaScript é composta por três partes distintas: o núcleo (ECMAScript), o Document Object Model (DOM), e o Browser Object Model (BOM). ECMAScript não está preso a nenhum navegador em particular. Um navegador web é considerado um ambiente hospedeiro para o ECMAScript, existindo inúmeros outros ambientes (como por exemplo o Macromedia ActionScript, utilizado no Flash). De maneira simplificada ECMAScript é uma descrição, definindo todas as propriedades, métodos, sintaxe e objetos de uma linguagem de scripting. Outras linguagens implementam o ECMAScript, como faz o JavaScript, utilizando-o como um ponto de partida de 35 funcionalidades. Cada navegador possui sua própria implementação da interface do ECMAScript, que é então extendida para conter o DOM e o BOM. O Document Object Model (DOM) é uma Application Programming Interface (API) para manipulação de HTML e XML. O DOM mapeia toda a página como um documento formado por uma hierarquia de nós. Através da criação de uma árvore para representar um documento, o DOM permite aos desenvolvedores um nível sem precedentes de controle sobre o conteúdo e a estrutura desse documento. Nós podem ser facilmente removidos, adicionados ou substituídos utilizando a API do DOM. Por sua importância e pelo fato de ser uma interface independente de linguagem de programação, o DOM será abordado separadamente no capítulo 5. A terceira parte do JavaScript, o Browser Object Model (BOM), permite o acesso e a manipulação da janela do navegador. Utilizando o BOM, desenvolvedores podem mover a janela, mudar o texto da barra de status, e realizar outras ações que não têm diretamente relação com o conteúdo da página. O que torna o BOM único, e freqüentemente problemático, é que ele é a única parte da implementação do JavaScript que não possui padronização. Por esse motivo, cada navegador possui sua própria implementação. Existem alguns padrões de fato, como a existência de um objeto window e um objeto navigator, mas cada navegador define suas próprias propriedades e métodos para esses e outros objetos. 4.1 Sintaxe A sintaxe do JavaScript empresta alguns elementos de linguagens como Java, C e Perl. Os conceitos básicos da linguagem, segundo Zakas (2005), são os seguintes: – Tudo é sensível à caixa (case-sensitive): variáveis, nomes de funções, operadores e todo o restante são case-sensitive (sensíveis ao tamanho da letra), ou seja, uma variável chamada test é diferente de uma outra chamada Test. – Variáveis são de tipo dinâmico: diferentemente de Java e C, não é definido um tipo específico às variáveis em JavaScript. Ao invés disso, cada variável é definida usando o operador var e pode ser inicializada com qualquer valor. Isso permite que seja alterado o tipo de dado que uma variável contém a qualquer momento (embora isso deva ser evitado). Por exemplo: var color = "azul"; var num = 25; var visible = true; – Ponto-e-vírgula no final da linha é opcional: Java, C e Perl requerem que toda linha termine com um ponto-e-vírgula para estar sintaticamente correta. JavaScript 36 permite ao desenvolvedor decidir se usa ou não um ponto-e-vírgula no final da linha. – Comentários são iguais a Java, C e Perl: JavaScript emprestou seus comentários dessas linguagens. Existem dois tipos de comentários: linha única e multilinha. Comentários de linha única começam com duas barras (//), enquanto que comentários multilinha começam com uma barra e um asterisco (/*) e terminam com um asterisco seguido de uma barra (*/), da seguinte forma: // este é um comentário de linha única /* este é um comentário multilinha */ – Colchetes indicam blocos de código: outro conceito emprestado do Java é o bloco de código. Blocos de código são usados para indicar uma série de expressões que devem ser executadas em seqüência e são indicados através do envolvimento das expressões entre um colchete de abertura ({) e um colchete de fechamento (}), como no código 5: if (test1 == "azul") { test1 = "vermelho"; alert(test1); } CÓDIGO 5 – Bloco de código em JavaScript. A construção de expressões e estruturas de controle em JavaScript é bastante semelhante às linguagens C, C++ e Java. As estruturas if-else, while, e for por exemplo apresentam bastante similaridade, como mostrado no código 6: // estrutura if-else if (i > 25) { alert("Maior que 25."); } else if (i < 0) { alert("Menor que 0."); } else { alert("Entre 0 e 25, inclusive."); } // estrutura for var iNum = 0; for (var i=1; i < 10; i++) { if (i % 5 == 0) { break; } iNum++; } alert(iNum); // exibe 4 CÓDIGO 6 – Estruturas if-else e for em JavaScript. 37 De acordo com Zakas (2005) os valores que as variáveis recebem podem ser divididos em dois grupos: valores primitivos (primitive values) ou valores referência (reference values). Valores primitivos são dados simples que são armazenados na pilha (stack), o que significa que são mantidos na localização diretamente acessada pela variável. Por outro lado, os valores referência são objetos armazenados na memória heap, o que quer dizer que o valor mantido no local acessado pela variável é um ponteiro para a localização em memória onde o objeto se encontra armazenado. Um valor é considerado primitivo quando faz parte de um dos conjuntos de valores definidos para cada um dos cinco tipos primitivos existentes em ECMAScript, que são: – Tipo Undefined: possui apenas um valor, undefined. Quando uma variável é declarada mas não é inicializada, ela recebe o valor undefined por padrão. – Tipo Null: também possui apenas um valor, null. Na verdade o valor undefined é um derivativo do valor null e ECMAScript os define como iguais, portanto a expressão "if (null == undefined)" é considerada verdadeira. Isso não quer dizer que ambos possuem o mesmo significado, pois enquanto undefined é utilizado para variáveis declaradas mas não inicializadas, null é o valor utilizado para representar um objeto que não existe. O fato de Null ser um tipo primitivo e apontar para um objeto é devido a um erro na implementação do JavaScript original que acabou sendo incorporado ao ECMAScript. Portanto, quando se espera que uma função ou método1 retorne um objeto, é retornado null quando o objeto não é encontrado. – Tipo Boolean: possui dois valores, true e false. Mesmo que false não seja igual a 0, 0 é convertido para false quando necessário, sendo seguro utilizá-lo em uma declaração booleana. – Tipo Number: pode representar valores inteiros de 32 bits e ponto flutuante de 64 bits. Para se declarar em uma variável um valor em ponto flutuante deve-se adicionar um ponto e um dígito após o ponto (1.0 ao invés de 1, por exemplo). Os valores limite suportados pelo tipo Number podem ser obtidos através de Number.MAX_VALUE (valor máximo) e Number.MIN_VALUE (valor mínimo). – Tipo String: pode armazenar zero ou mais caracteres Unicode, representados por números inteiros de 16 bits. Diferentemente dos valores primitivos, os valores referência lidam com objetos. Conforme define ECMA (1999) no padrão ECMA-262, um objeto é "uma coleção não ordenada de propriedades, cada qual contendo um valor primitivo, objeto, ou função", o que significa em outras palavras que um objeto é um vetor de valores sem ordenamento. Cada objeto é, ainda de acordo com o ECMA-262, determinado por uma definição de objeto 1 ECMA-262 define que "uma função armazenada como propriedade de um objeto é chamada de método". 38 (object definition), que estabelece a interface do objeto (suas propriedades e métodos) e seu funcionamento interno (o código que faz o objeto funcionar). As objects definitions são semelhantes em funcionalidade às classes das linguagens orientadas a objeto. A maneira como os objetos são criados (ou instanciados) também é semelhante à das linguagens orientadas a objeto C++ e Java: utiliza-se a palavra-chave new seguida pelo nome do objeto. O código 7 mostra a criação do objeto Array e a utilização da propriedade length e do método toString: var array_cores = new Array(); // cria objeto Array array_cores[0] = "azul"; array_cores[1] = "laranja"; array_cores[2] = "verde"; alert(array_cores.length); // exibe 3 alert(array_cores.toString()); // exibe "azul,laranja,verde" CÓDIGO 7 – Criação e utilização de um objeto Array. Os objetos em ECMAScript podem ser de três tipos: – Objetos nativos (Native objects): são aqueles disponíveis em uma implementação ECMAScript que independem do ambiente hospedeiro. Ou seja, são os objetos definidos pelo padrão ECMA-262. Exemplos são os objetos Array, Date, Function, e Error. – Objetos embutidos (Built-in objects): trata-se de qualquer objeto disponível na implementação ECMAScript que, além de independente do ambiente hospedeiro, está presente no início da execução de um programa ECMAScript. Isso significa que não é necessário criá-lo (ou instanciá-lo) explicitamente pelo desenvolvedor, pois ele já se encontra criado. Os dois únicos objetos embutidos definidos pelo ECMA-262 são Global e Math. Por definição, todo objeto embutido também é um objeto nativo. – Objetos do hospedeiro (Host objects): é definido pelo ECMA-262 como sendo qualquer objeto fornecido pelo ambiente hospedeiro, com o propósito de complementar o ambiente de execução do ECMAScript. Todo objeto que não é nativo é um objeto do hospedeiro. Portanto, os objetos do BOM e do DOM são considerados objetos deste tipo, já que são providos pelo ambiente hospedeiro (navegador web). Os conceitos relativos à definição e funcionamento dos objetos em JavaScript são particularmente importantes, pois os host objects são essenciais ao funcionamento da técnica Ajax. São os objetos do DOM e do BOM que permitem a atualização dinâmica da interface do usuário e é através do objeto XMLHttpRequest que é realizada a comunicação 39 assíncrona para troca de dados entre cliente e servidor. Dado sua importância, tais objetos serão abordados em maior detalhe mais adiante. 4.2 Browser Object Model Segundo Zakas, (2005) o BOM é constituído por uma série de objetos que interagem com a janela do navegador, independentemente do conteúdo. Tais objetos relacionam-se entre si de acordo com a hierarquia exibida na figura 7: FIGURA 7 – Hierarquia de objetos no BOM. Através da hierarquia pode-se notar que o objeto window é o ponto central do BOM. Ele representa toda a janela do navegador, mas não necessariamente o conteúdo que a janela contém. Isso significa que o objeto pode ser utilizado para, por exemplo, mover, redimensionar, ou de alguma maneira alterar o comportamento do navegador que ele representa. Se uma página utiliza framesets, cada frame é representado pelo seu próprio objeto window e armazenado na coleção de frames. Dentro dessa coleção, os objetos window são indexados (da esquerda para a direita, de cima para baixo), tanto por número, quanto por nome do frame. Considerando o seguinte documento HTML do código 8: 40 <html> <head> <title>Exemplo de página com framesets</title> </head> <frameset rows="70,*"> <frame src="frame.htm" name="Frame_cima" /> <frameset cols="50%,50%"> <frame src="outroframe.htm" name="Frame_esq" /> <frame src="outroframe2.htm" name="Frame_dir" /> </frameset> </frameset> </html> CÓDIGO 8 – Documento HTML usando framesets. O código HTML acima cria um frame no alto da página e dois frames lado a lado abaixo. Neste caso, os frames podem ser referenciados da seguinte maneira: – Frame no alto da página: window.frames[0] ou window.frames["Frame_cima"]; – Frame abaixo à esquerda: window.frames[1] ou window.frames["Frame_esq"]; – Frame abaixo à direita: window.frames[2] ou window.frames["Frame_dir"]. Pelo fato do objeto window ser o ponto principal do BOM, ele apresenta a característica de não ser necessário referenciá-lo diretamente. Isso significa que é possível reescrever window.frames[0] como frames[0], ou ainda window.frames["Frame_cima"] como frames["Frame_cima"]. Como mencionado anteriormente, através do objeto window é possível mover ou redimensionar a janela do navegador. Existem quatro métodos disponíveis para realizar essa tarefa: – moveBy(x, y): move a janela do navegador x pixels horizontalmente e y pixels verticalmente, relativamente à posição atual. Pode-se utilizar números negativos em x para mover a janela para esquerda e em y para mover para cima. – moveTo(x, y): move a janela do navegador de maneira que o canto superior esquerdo fique localizado na posição (x, y) da tela do usuário. Pode-se utilizar números negativos, porém isso faz com que parte da janela fique fora da tela. – resizeBy(w, h): redimensiona a largura (width) da janela em w pixels e a altura (height) em h pixels, relativamente ao tamanho atual. Pode-se utilizar números negativos em w para diminuir a largura e em h para diminuir a altura. – resizeTo(w, h): redimensiona a janela do navegador para w pixels de largura e h pixels de altura. Não é possível utilizar números negativos. Para realizar as operações de movimentação e redimensionamento de janelas, por vezes se faz necessário acessar as informações relativas ao posicionamento e tamanho atual da janela. O BOM, como já citado, não possui um padrão definido a ser seguido e 41 nesse ponto é possível notar a falta de padronização entre os navegadores. Para determinar a posição da janela, o navegador Internet Explorer provê as propriedades window.screenLeft e window.screenTop, enquanto que Mozilla, Opera e Safari disponibilizam window.screenX e window.screenY. Determinar o tamanho da janela do navegador no Internet Explorer não é possível, apenas é permitido determinar o tamanho do viewport, que é a área na qual a página HTML é exibida, através das propriedades document.body.offsetWidth e document.body.offsetHeight. Os outros três navegadores apresentam as propriedades window.innerWidth e window.innerHeight para determinação do tamanho do viewport, além de window.outerWidth e window.outerHeight para o tamanho real da janela do navegador. O objeto window também permite que novas janelas do navegador sejam abertas através do método window.open(). Usualmente, o método é utilizado com três argumentos: a URL da página a ser carregada na nova janela, o nome da janela e uma string de atributos separados por vírgula. Caso o método seja chamado com o nome de um frame existente como segundo argumento, a URL é então carregada neste frame. O código 9 a seguir abre uma nova janela com altura de 150 e largura de 300 pixels (height=150, width=300), localizada na posição (10, 10) da tela (top=10, left=10) e podendo ser redimensionada (resizable=yes): /* abre uma nova janela com o nome de janela_2 e carrega a página do Gmail */ window.open("http://www.gmail.com/","janela_2","height=150,width=300,top=10,left =10,resizable=yes"); CÓDIGO 9 – Uso do método window.open(). Além de abrir novas janelas, também é possível utilizar três tipos de janelas de diálogo: – window.alert(): esse método recebe um argumento, que é o texto a ser exibido para o usuário. Quando alert() é chamado, o navegador cria uma caixa de mensagem do sistema e exibe o texto definido juntamente com o botão "OK". Freqüentemente alert() é utilizado para avisar o usuário quando este submeteu dados inválidos em um formulário. – window.confirm(): é parecido com o diálogo de alerta, a principal diferença é a exibição de um botão de "Cancelar" além do botão de "OK", o que permite ao usuário indicar se uma determinada ação deve ser realizada. Para determinar qual botão o usuário pressionou, confirm() retorna true se "OK" foi selecionado e false caso "Cancelar" tenha sido selecionado. – window.prompt(): exibe uma caixa de diálogo que permite a entrada de dados pelo usuário. Juntamente com os botões de "OK" e "Cancelar" é exibida uma caixa de 42 texto na qual solicita-se que o usuário entre alguma informação. O método prompt() recebe dois argumentos: o texto a ser exibido ao usuário e um valor padrão para a caixa de texto (podendo ser um valor vazio). O código 10 mostra a utilização das três janelas de diálogo em uma função que exibe uma mensagem de boas vindas ao usuário. As janelas do exemplo podem ser visualizadas na figura 8: // caso o usuário clique em "Cancelar" a mensagem não é exibida. function mostra_msg() { var resp = confirm("Deseja visualizar a mensagem de boas vindas?"); if(resp == true) { var nome = prompt("Informe seu nome:", "Nome"); if(nome == null) { alert("Ação cancelada."); } else { alert("Olá "+nome+"! Bem vindo ao sistema!"); } } else { alert("Mensagem cancelada."); } } CÓDIGO 10 – Utilização das janelas de diálogo alert(), confirm() e prompt(). FIGURA 8 – Janelas de diálogo confirm(), prompt() e alert(). 43 O BOM disponibiliza mais uma série de funcionalidades, além das já citadas, através dos seguintes métodos e objetos: – Método window.setTimeout(): permite que um determinado código seja executado após um número de milisegundos especificado. Por exemplo, para exibir um aviso ao usuário dentro de cinco segundos utiliza-se: setTimeout("alert('Aviso! Verifique seu e-mail!')",5000). – Método window.setInterval(): semelhante ao setTimeout(), com a diferença que o código passado como argumento é executado repetidamente no intervalo especificado. Para repetir o aviso do código anterior de um em um segundo, podese utilizar setInterval("alert('Aviso! Verifique seu e-mail!')", 1000). – Objeto window.history: através do objeto history é possível acessar o histórico de uma janela do navegador. Por razões de segurança não há uma maneira de saber quais foram as URLs visitadas, apenas é possível navegar pelo histórico. Para isso, utiliza-se o método go() passando o número de páginas à frente ou para trás (neste caso usando um número negativo). Por exemplo, para voltar duas páginas no histórico, utiliza-se o código window.history.go(-2). Também existem, além de go(), os métodos history.back() (voltar uma página) e history.forward() (avançar uma página). – Objeto location: representa a URL carregada na janela do navegador e possui várias propriedades representando segmentos da URL como location.host, (representa o nome do servidor, como em www.google.com) e location.pathname, (representa a parte da URL depois do nome do servidor). A propriedade location.href é a mais utilizada, pois representa a URL atualmente carregada na página e alterando seu valor é possível navegar para outra página. Por exemplo, location.href = "http://www.mozilla.org" envia o navegador ao endereço especificado. Também é possível recarregar a página atual através do método location.reload(). O objeto location é uma propriedade tanto de window (window.location) quanto de document (window.document.location ou document.location), sendo o mesmo objeto nos dois casos e podendo portanto ser usado das duas formas indistintamente. – Objeto window.screen: disponibiliza informações sobre a tela do usuário. Como costuma ocorrer, cada navegador possui propriedades específicas para o objeto, mas existem entre os navegadores as propriedades comuns screen.availHeight (altura da tela disponível para a janela em pixels, levando em consideração elementos da interface do usuário, como por exemplo a barra de tarefas no sistema operacional Windows), screen.availWidth (largura da tela disponível), screen.colorDepth (número de bits para representação de cores), screen.height 44 (altura total da tela) e screen.width (largura total da tela). As propriedades availHeight e availWidth são particularmente úteis quando se deseja exibir uma janela em tela cheia, por exemplo. Outro objeto do BOM, o window.navigator, fornece várias informações sobre o navegador web, sendo bastante útil na determinação de qual navegador está sendo utilizado. Várias técnicas de detecção de navegador e sistema operacional fazem uso desse objeto com a finalidade de determinar se o navegador é capaz de executar a aplicação web. O código 11 exibe sua utilização: if(navigator.userAgent.indexOf("Opera") > -1) alert("Você está utilizando o navegador Opera."); else if(navigator.userAgent.indexOf("MSIE") > -1) alert("Você está utilizando o navegador Internet Explorer."); else if(navigator.userAgent.indexOf("Firefox") > -1) alert("Você está utilizando o navegador Firefox."); else alert("Não foi possível detectar o seu navegador."); CÓDIGO 11 – Emprego do objeto navigator para detecção do navegador em uso. Segundo Zakas (2005) além dessa técnica de detecção, conhecida como detecção pela string do user-agent (sendo user-agent o navegador), existe a técnica de detecção por objeto/funcionalidade, que busca determinar se um dado objeto ou método está disponível antes de usá-lo. A maioria dos desenvolvedores JavaScript aponta essa última como mais apropriada por tornar o código imune a mudanças que possam dificultar a determinação do navegador em uso. A correta determinação das funcionalidades do navegador é ponto importante na utilização da abordagem Ajax, pois certas funcionalidades estão disponíveis de forma diferente entre os navegadores ou, em versões mais antigas, não estão disponíveis. Realizar uma correta detecção permite que a aplicação funcione livre de erros e, nos casos em que o navegador é antigo, que o usuário seja corretamente informado da situação, economizando esforços tanto do desenvolvedor quanto do usuário da aplicação. O último objeto pertencente ao BOM é o window.document, que apresenta a característica única de pertencer tanto ao BOM quanto ao DOM2. Da perspectiva do BOM, o objeto window.document constitui-se de uma série de coleções que acessam várias partes do documento, além de propriedades que fornecem informações sobre a página em si. As coleções e propriedades principais são: 2 A forma como o objeto document relaciona-se com o DOM é abordada no capítulo 5. 45 – document.anchors: coleção de todas as âncoras da página (representadas por <a name="nome_da_ancora"></a>); – document.forms: coleção que contempla todos os formulários da página; – document.images: coleção referenciando todas as imagens da página; – document.links: coleção contendo todos os links da página (representados por <a href="pagina.htm"></a>); – document.title: propriedade que contém o texto da tag <title> (título da página); – document.referrer: propriedade contendo a URL da posição imediatamente anterior no histórico do navegador; – document.URL: propriedade contendo a URL da página atual. De maneira similar à coleção window.frames, cada uma das coleções do objeto document são indexadas tanto por número quanto por nome, o que significa que é possível acessar um elemento usando document.images[0] ou document.images["nome_imagem"]. O objeto document também possui dois métodos bastante utilizados: document.write() e document.writeln(). Ambos aceitam um argumento, que é a string a ser escrita no documento, sendo a única diferença a adição de uma quebra de linha ao final da string em writeln(). Os métodos inserem a string de texto no documento no ponto onde foram executados, e o navegador a trata como se fosse parte do HTML normal da página. A string deve ser inserida antes do fim do carregamento do documento, caso contrário todo o documento será substituído pela string de texto passada ao método. O estudo do Browser Object Model permite notar sua contribuição ao desenvolvimento Ajax, pois ele disponibiliza uma série de funcionalidades que provêm interatividade às aplicações web. O ponto a ser ressaltado é relativo à falta de padronização entre os diferentes navegadores na utilização do BOM: o desenvolvedor Ajax deve estar atento para garantir a compatibilidade entre navegadores através de técnicas de identificação do useragent, como a demonstrada utilizando o objeto navigator, ou através da detecção das funcionalidades disponíveis, procurando definir previamente se um dado objeto, método ou propriedade está presente antes de utilizá-lo. 4.2 Eventos Conforme explica Zakas (2005) a interação entre o código JavaScript e o documento HTML é gerenciada através de eventos, que ocorrem quando o usuário ou o navegador manipulam a página de alguma maneira. Vários tipos de operações são considerados eventos, como quando a página é carregada ou quando um usuário realiza um clique no mouse. Através dos eventos é possível codificar respostas fazendo com que botões fechem 46 janelas, mensagens sejam exibidas ao usuário e dados sejam validados. Em suma, o mecanismo de eventos permite que a página interaja com o usuário e o navegador, respondendo às ações que estes realizam. Os eventos fazem parte do Document Object Model, porém seu completo desenvolvimento pelo DOM ocorreu apenas em 2004. Portanto, à época da criação do modelo de eventos nos navegadores, não haviam padrões a serem usados como referência pelos desenvolvedores, levando Internet Explorer e Netscape a criarem seus próprios modelos de eventos. Quando a Netscape liberou seu código fonte para a comunidade de código aberto (Open Source) sob o nome Mozilla, os desenvolvedores-chave procuraram aderir aos padrões e os navegadores Opera e Safari também adotaram o padrão do DOM, deixando o Internet Explorer como o único dos principais navegadores sem o suporte apropriado ao modelo de eventos do DOM. No restante da abordagem dos eventos em JavaScript, serão vistas as diferenças entre os dois modelos de eventos. Os eventos que ocorrem no navegador podem ser separados em quatro grupos, dependendo do objeto que disparou o evento e do que causou a ocorrência deste. O DOM define os seguintes grupos de eventos: – Eventos de mouse: ocorrem quando o usuário utiliza o mouse para realizar uma ação. Os eventos podem ser click (clique do botão esquerdo), dblclick (duplo clique do botão esquerdo), mousedown (qualquer botão é pressionado), mouseout (cursor move-se para fora do foco do elemento), mouseover (cursos move-se para dentro do foco do elemento), mouseup (qualquer botão deixa de ser pressionado) e mousemove (qualquer movimentação do cursor é realizada sobre o elemento). – Eventos de teclado: ocorrem quando o usuário realiza uma digitação no teclado, podendo ser keydown (tecla é pressionada), keypress (tecla é pressionada, mas neste caso o retorno é um caractere para teclas de caractere e teclas como Shift e Alt são ignoradas) e keyup (tecla deixa de ser pressionada). – Eventos HTML: são disparados quando certas mudanças ocorrem na janela do navegador ou em uma interação específica entre cliente e servidor. Este tipo de evento possui uma série de possibilidades: 1. load: elemento termina de ser carregado; 2. unload: elemento termina de ser descarregado; 3. abort: processo de download é interrompido e o elemento não foi carregado; 4. error: para o objeto window é disparado quando ocorre um erro de JavaScript e para elemento quando este não pode ser carregado; 5. select: usuário seleciona um ou mais caracteres em uma caixa de texto (<input> ou <textarea>); 6. submit: botão Submit de um <form> é pressionado; 47 7. reset: botão Reset de um <form> é pressionado; 8. resize: ocorre quando uma janela ou frame é redimensionado; 9. scroll: é disparado quando o usuário rola a barra de rolagem de um elemento; 10. focus: elemento recebe o foco (através de clique ou interação); 11. blur: disparado no momento em que o elemento perde o foco. – Eventos de mutação (Mutation events): disparados quando acontecem mudanças na estrutura DOM da página. Este tipo de evento ainda não foi implementado nos navegadores, apesar de fazer parte da especificação DOM. Dois exemplos especificados pelo DOM para esse tipo de evento são DOMNodeInserted (nó é inserido como filho de outro nó) e DOMNodeRemoved (nó é removido como filho de outro nó). Quando um botão recebe um clique em uma página, na verdade não só ele está recebendo o clique, mas também o elemento que o contém (uma tabela, por exemplo) e a página como um todo. Logicamente cada um dos elementos deve responder ao evento em uma ordem específica. O fluxo de eventos (ou a ordem em que cada elemento responde) é diferente entre o modelo Internet Explorer e o modelo DOM. No caso do IE, foi desenvolvido um fluxo de eventos conhecido como event bubbling. Ele consiste em disparar o evento seqüencialmente a partir do alvo mais específico para o menos específico (o objeto document, que é a raiz da árvore do DOM). Por exemplo, no caso da página do código 12, a ordem de ocorrência do evento seria: div, body, html e document (nas versões anteriores ao IE 6.0 o elemento html não recebe o evento, passando direto de body para document). <html> <head> <title>Exemplo</title> </head> <body> <div onclick="funcao()">Clique aqui</div> </body> </html> CÓDIGO 12 – Documento HTML. 48 FIGURA 9 – Modelo event bubbling de fluxo de evento. No DOM, o fluxo de evento, além de suportar o event bubbling, suporta o event capturing, um modelo de fluxo de evento que era utilizado pelo navegador Netscape 4.0. Ele consiste exatamente no oposto do bubbling: dispara o evento do elemento menos específico (objeto document) para o mais específico. No DOM, o capturing ocorre primeiro e em seguida ocorre o bubbling, ambos passando por todos os elementos, começando a partir e terminando no objeto document (a maioria dos navegadores que seguem o DOM utiliza o objeto window como referência no lugar de document). O fluxo de evento do código 12 em um navegador que segue o DOM é o exibido na figura 10: FIGURA 10 – Modelo DOM de fluxo de evento. 49 Eventos são ações realizadas pelo usuário ou pelo próprio navegador. Para responder a um evento uma função é chamada, a qual se dá o nome de event handler (ou manipulador de evento). Uma função que responde a um evento click (clique do mouse) é considerada a manipuladora do evento onclick. Tradicionalmente, event handlers são designados de duas maneiras: no código JavaScript ou no documento HTML. Para designar um manipulador de evento no JavaScript, deve-se definir uma referência ao objeto ao qual o manipulador será designado e então atribuir uma função à propriedade event handler correspondente ao evento em questão, conforme pode ser visto no código 13: var div_1 = document.getElementById("div_1"); div_1.onclick = function () { alert("Clique recebido"); }; CÓDIGO 13 – Atribuição de event handlers a objeto no código JavaScript. No caso do HTML, basta adicionar à tag HTML o atributo referente ao manipulador de evento, inserindo como valor deste o código JavaScript desejado, da seguinte maneira: <div id="div_1" onclick="alert('Clique recebido')"></div> Ambos os métodos funcionam nos navegadores modernos, mas métodos adicionais permitem que mais de um manipulador seja designado por evento. Novamente, Internet Explorer possui um método e o DOM possui outro. No IE, todo elemento possui dois métodos: attachEvent() e detachEvent(). O primeiro é utilizado para anexar um manipulador a um evento e o segundo é usado para remover um manipulador de evento. Ambos recebem dois argumentos: o nome do evento ao qual o manipulador será designado (ondoubleclick, por exemplo) e uma função. No caso de attachEvent() a função é adicionada como um manipulador de evento; no caso de detachEvent() este procura pela função na lista de manipuladores e a remove. var recebe_click1 = function () { alert("Clique recebido"); }; var recebe_click2 = function () { alert("Clique recebido novamente"); }; var div_1 = document.getElementById("div_1"); div_1.attachEvent("onclick", recebe_click1); div_1.attachEvent("onclick", recebe_click2); CÓDIGO 14 – Atribuição de event handlers no Internet Explorer. 50 Como mencionado, o método pode ser utilizado para adicionar mais de um manipulador de evento. O código 14 faz com que dois alertas sejam exibidos quando o elemento <div> é clicado. Primeiramente o “Clique recebido”, seguido pelo “Clique recebido novamente”. Os manipuladores de evento são sempre executados na ordem em que foram adicionados. No caso do DOM, a tarefa de adicionar e remover manipuladores de evento é feita pelos métodos addEventListener() e removeEventListener(). Diferentemente do IE, eles recebem três argumentos: o nome do evento, a função a ser designada, e se o manipulador deve ser usado na fase de bubbling ou de capturing. Para capturing o parâmetro deve ser true, para bubbling, false. Da mesma maneira que o IE, pode-se adicionar mais de um manipulador para o evento: var recebe_click1 = function () { alert("Clique recebido"); }; var recebe_click2 = function () { alert("Clique recebido novamente"); }; var div_1 = document.getElementById("div_1"); div_1.addEventListener("click", recebe_click1, false); div_1.addEventListener("click", recebe_click2, false); CÓDIGO 15 – Atribuição de event handlers de acordo com o DOM. O código 15 produz o mesmo resultado que o exibido no código 14, apenas com a diferença relativa à utilização do método DOM addEventListener() ao invés de attachEvent() do IE. Deve-se notar que se o manipulador de evento é adicionado para uma determinada fase (capturing ou bubbling), é preciso especificar esta mesma fase ao removê-lo com removeEventListener(), caso contrário a função não será removida. Um ponto importante sobre manipuladores de evento no DOM é que se a maneira tradicional, que consiste em designar uma função diretamente à propriedade event handler do objeto, é utilizada, o manipulador de evento é adicionado para a fase de bubbling. Assim, as duas linhas de código a seguir possuem o mesmo efeito: div_1.onclick = recebe_click1; // maneira tradicional div_1.addEventListener("click", recebe_click1, false); // método DOM Se as duas linhas fossem inseridas em um código e o segundo argumento de addEventListener fosse recebe_click2() ao invés de recebe_click1(), seriam adicionados dois manipuladores de evento (recebe_click1 e recebe_click2), ambos para a fase de bubbling. É importante lembrar que a maneira tradicional não permite que mais de um manipulador seja associado ao objeto, de forma que caso a segunda linha fosse substituída 51 pelo código “div_1.onclick = recebe_click2;”, o manipulador deixaria de ser a função recebe_click1() e passaria a ser recebe_click2(). Definida a função (ou funções) responsável por processar o evento, se faz necessário que ela tenha acesso a informações relativas ao evento ocorrido. Zakas (2005) explica que para isso criou-se um objeto evento (event object) contendo informações específicas sobre o evento que acabou de ocorrer, tais como: – O objeto que causou o evento; – Informações sobre o mouse no momento do evento; – Informações sobre o teclado no momento do evento. Os objetos evento são criados quando este ocorre e se são acessíveis pelos manipuladores do evento. Depois que todos os manipuladores foram executados, o objeto evento é destruído. Como esperado, o Internet Explorer e o DOM implementam o objeto evento de maneiras diferentes. No Internet Explorer, o objeto evento é uma propriedade do objeto window. Isso significa que um manipulador de evento deve acessar o objeto através de “window.event”. Mesmo sendo uma propriedade de window, o objeto window.event é acessível apenas quando um evento ocorre. Depois que todos os manipuladores são executados, esse objeto é destruído. O padrão DOM, por sua vez, determina que o objeto evento deve ser passado como único argumento ao manipulador de evento. Goodman (2001) ensina uma maneira de implementar uma detecção do objeto event de forma independente do navegador utilizado: function executa_acao(evt) { evt = (evt) ? evt : (window.event) ? window.event : ""; if (evt) { // processa ação } } CÓDIGO 16 – Técnica para detecção do objeto event. Se o objeto evento é passado como parâmetro da função (modelo DOM), este continua disponível como evt; caso contrário a função verifica se o objeto window.event está disponível (modelo IE) e o atribui a evt; por fim, se ainda assim não há um objeto evento disponível, a variável evt se torna vazia, e o processamento da função só continua se evt possuir um objeto evento. Acessar as propriedades e métodos do objeto event pode ser uma tarefa mais difícil do que detectá-lo, devido às variações nos nomes das propriedades e métodos entre os modelos. Ainda assim, eles apresentam propriedades semelhantes, sendo as principais as seguintes: 52 – Tipo do evento: para saber qual o tipo do evento ocorrido, utiliza-se a propriedade type (evt.type), que retorna um valor contendo o nome do evento (como “click”, “mouseover” ou “doubleclick”, por exemplo). – Código da tecla: em um evento keydown ou keyup, é possível saber o código da tecla que foi pressionada através da propriedade keyCode (evt.keyCode). No caso da tecla Enter o código é 13, a barra de espaço é 32 e a tecla Backspace é 8. – Coordenadas do mouse na área do cliente: durante eventos do mouse, é possível acessar a localização do cursor do mouse em relação à parte da janela que exibe a página web (chamada de área do cliente), através das propriedades clientX (evt.clientX, coordenada do eixo x) e clientY (evt.clientY, coordenada do eixo y). As coordenadas dizem o quão longe em pixels o cursor do mouse está do início da área do cliente; – Coordenadas do mouse na tela: de maneira análoga às propriedades clientX e clientY, é possível em eventos do mouse acessar a localização do cursor em relação à tela do computador através das propriedades screenX (evt.screenX) e screenY (evt.screenY). Com relação às diferenças entre Internet Explorer e DOM, as principais propriedades e métodos são: – Alvo do evento: o objeto que é o centro de um evento é chamado de alvo. Supondo que seja atribuído um manipulador para o evento onclick ao elemento <div>, no momento em que o evento click é disparado o elemento <div> é considerado o alvo. No Internet Explorer, a propriedade que contém o alvo é srcElement (evt.srcElement), enquanto que no DOM o nome da propriedade é target (evt.target). – Bloquear o comportamento padrão do evento: para impedir que ocorra o comportamento padrão de um evento no IE, deve-se atribuir o valor false à propriedade returnValue (“evt.returnValue = false;”). No DOM, utiliza-se o método preventDefault() (“evt.preventDefault();”). Bloquear o comportamento padrão do evento pode ser útil quando se deseja, por exemplo, rejeitar um determinado caractere que é digitado em uma caixa de texto, ou impedir o uso pelo usuário do menu de contexto que aparece quando este realiza um clique sobre a página com o botão direito do mouse. – Código do caractere: em eventos do tipo keypress é possível saber o valor Unicode da tecla pressionada caso esta represente um caractere. No IE, esse valor é acessível através da propriedade keyCode (evt.keyCode) vista anteriormente 53 enquanto que no DOM keyCode é 0, e o valor Unicode é disponibilizado pela propriedade charCode (evt.charCode). – Parar a propagação do evento: para impedir a propagação (bubbling) do evento no Internet Explorer, deve-se atribuir o valor true à propriedade cancelBubble (“evt.cancelBubble = true;”). No DOM, isto é feito através da chamada ao método stopPropagation() (“evt.stopPropagation();”). Parar a propagação do evento faz com que os manipuladores (event handlers) de outros objetos no fluxo do evento não sejam executados. Zakas (2005) define os eventos como um dos conceitos mais importantes em JavaScript, sendo a principal maneira de anexar JavaScript a uma interface web. Os eventos capturam praticamente qualquer ação que o usuário realiza enquanto está interagindo com a interface, conferindo ao desenvolvedor grande flexibilidade no desenvolvimento de aplicações web. 4.4 O objeto XMLHttpRequest Conforme explicam Crane et al. (2006) o objeto XMLHttpRequest é uma extensão nãopadrão suportada pela maioria dos navegadores web. Ele dinamiza o trabalho de realizar chamadas assíncronas consideravelmente, pois é concebido explicitamente para buscar dados em segundo plano. De acordo com Jacobs (2006) o objeto XHR se encontra no coração da abordagem Ajax, permitindo a páginas web requisitar dados de um servidor utilizando código do lado cliente. O XMLHttpRequest originou-se como um componente ActiveX específico da Microsoft, disponibilizado como um objeto JavaScript no navegador Internet Explorer. Outros navegadores então o implementaram como um objeto nativo, e atualmente os principais navegadores (Firefox, Safari, Opera, Konqueror e IE) implementam o comportamento do objeto de maneira similar. Para que o XHR possa ser utilizado para enviar requisições e processar respostas, Asleson e Schutta (2006) esclarecem que primeiramente é necessário instanciá-lo. Visto que não se trata de um padrão W3C e que o Internet Explorer implementa o XMLHttpRequest como um objeto ActiveX, enquanto que os demais como um objeto JavaScript nativo3, o código JavaScript precisa conter a lógica necessária para poder criar o objeto tanto utilizando a técnica ActiveX quanto JavaScript. O seguinte código, extraído de 3 No Internet Explorer 7 o objeto pode ser utilizado tanto de maneira nativa quanto através do ActiveX. 54 Jacobs (2006, p. 268), exemplifica como instanciar o objeto independentemente do navegador utilizado: var xmlhttp = false; if (window.XMLHttpRequest) { // navegadores Mozilla, Opera ou Safari xmlhttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { // navegador Internet Explorer try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) { xmlhttp = false; } } } CÓDIGO 17 – Criação de um objeto XMLHttpRequest. O motivo de se tentar instanciar duas vezes o objeto ActiveX em um bloco try-catch é devido ao fato da biblioteca MSXML (que contém o objeto XHR) possuir várias versões diferentes. Uma maneira de utilizar sempre a versão mais recente disponível é criar um vetor contendo todas as versões conhecidas e através de um laço for tentar instanciar o objeto para cada elemento do vetor (a partir da versão mais recente) até que a operação seja bem sucedida. De acordo com Darie et al. (2006) o objeto XHR possui os seguintes métodos e propriedades: – abort(): interrompe a requisição atual; – getAllResponseHeaders(): retorna uma string com todos os cabeçalhos da resposta HTTP; – getResponseHeader(“nome_cabeçalho”): retorna uma string contendo um único cabeçalho de resposta; – open(“metodo”, “URL”, indicador_assinc, “nome_usuario”, “senha”): inicializa os parâmetros da requisição; – send("conteúdo"): realiza a requisição HTTP; – setRequestHeader(“nome”, “valor”): define um par nome/valor para o cabeçalho da requisição; – onreadystatechange: define a função que manipula as mudanças de estado da requisição; 55 – readyState: retorna o status atual da requisição. Jacobs (2006) define os seguintes valores possíveis: 0: Requisição ainda não foi inicializada. Ocorre antes da chamada ao método open(); 1: Requisição inicializada mas não enviada. Ocorre antes da chamada ao método send(); 2: Requisição enviada e sendo processada; 3: Requisição send processada mas ainda não terminada; 4: A resposta está completa. – responseText: retorna uma string contendo a resposta do servidor; – responseXML: retorna a resposta do servidor no formato de um documento XML; – status: retorna o código de status HTTP da resposta do servidor; – statusText: retorna a mensagem relativa ao status da resposta. O próximo passo depois de criado o objeto é definir, através da propriedade onreadystatechange, a função a ser executada cada vez que o status da requisição (propriedade readyState) muda. Em seguida, deve-se utilizar o método open() para inicializar a requisição, configurando as opções da conexão. O primeiro parâmetro de open() especifica o método usado para enviar dados ao servidor, usualmente GET ou POST. O segundo parâmetro é a URL, que especifica para onde será feita a requisição (caso seja especificado um recurso não disponível via HTTP, o primeiro parâmetro é ignorado). O terceiro parâmetro especifica se a requisição deve ser feita de maneira assíncrona; true significa que o processamento continua depois que o método send() retorna, sem aguardar por uma resposta deste, enquanto que false faz com que seja aguardada uma resposta antes de continuar o processamento, paralisando a funcionalidade da página web. Portanto, deve-se utilizar o valor true para habilitar o processamento assíncrono e processar a resposta do servidor a partir da manipulação do evento onreadystatechange. Ao utilizar-se GET, os parâmetros são enviados através da query string da URL, como em http://algumhost.com/teste.php?param_1=cliente¶m_2=20 (essa requisição envia param_1 com o valor cliente e o param_2 com o valor 20). Com GET, os parâmetros são enviados na chamada ao método open(): xmlhttp.open("GET", "http://algumhost.com/teste.php?param_1=cliente¶m_2=20", true); xmlhttp.send(null); Quando POST é utilizado, os parâmetros são enviados através do método send(), no momento em que este dispara a requisição: 56 xmlhttp.open("POST", "http://algumhost.com/teste.php", true); xmlhttp.send("param_1=cliente¶m_2=20"); Asleson e Schutta (2006) explicam que POST deve ser usado quando a requisição gerar alguma mudança de estado (alteração de um banco de dados no servidor, por exemplo), e GET quando o intuito é buscar dados do servidor. Também existe entre os dois métodos uma diferença na quantidade de dados que pode ser enviada: no caso do GET, muitos navegadores e servidores limitam o tamanho da URL usada para enviar dados ao servidor, o que não ocorre com POST. Feita a requisição, a resposta do servidor pode ser processada uma vez que a propriedade readyState possua o valor 4. Se o código de status da resposta for 200, a requisição foi processada com sucesso (outros valores como 404 ou 500 indicam erro) e o conteúdo pode ser acessado através da propriedade responseText, ou como um documento XML através de responseXML. É importante lembrar que por questões de segurança, não é possível requisitar conteúdo de um dominío diferente daquele onde se encontra o script que originou a chamada ao objeto. Jacobs (2006) define essa característica como caixa de areia do Ajax (Ajax sandbox). No código 18 é exibido todo o fluxo de funcionamento do objeto XMLHttpRequest. Neste exemplo, quando o usuário pressiona o botão “Ver mensagem” é feita uma requisição HTTP ao servidor para acessar o arquivo texto mensagem.txt e exibir seu conteúdo na tela. A figura 11 exibe a mensagem com o conteúdo recebido. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Exemplo de uso - objeto XMLHttpRequest</title> <script type="text/javascript"> var xmlhttp = null; // função para instanciar o objeto function CriaObjetoXHR() { if (window.XMLHttpRequest) { // navegadores Mozilla, Opera ou Safari xmlhttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { // navegador Internet Explorer var XmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'); // loop for para procurar instanciar a versão mais recente do objeto for(var i=0; i < XmlHttpVersions.length && !xmlhttp; i++) { try { 57 xmlhttp = new ActiveXObject(XmlHttpVersions[i]); } catch(e) { xmlhttp = null; } } } } // funcao responsavel por realizar a requisicao ao servidor function RealizaRequisicao() { CriaObjetoXHR(); if(!xmlhttp) { alert ("Nao foi possivel realizar a operacao."); return; } xmlhttp.onreadystatechange = ProcessaResposta; xmlhttp.open("GET", "http://localhost/mensagem.txt", true); xmlhttp.send(null); } // funcao que processa a resposta do servidor, exibindo o conteudo do arquivo function ProcessaResposta() { if(xmlhttp.readyState == 4) { if(xmlhttp.status == 200) { var conteudo = xmlhttp.responseText; alert(conteudo); } else { alert("Ocorreu um erro no processamento da resposta."); } } } </script> </head> <body> <div style="text-align:center"> <input value="Ver mensagem" type="button" onclick="RealizaRequisicao()"> </div> </body> </html> CÓDIGO 18 – Utilização do objeto XMLHttpRequest. FIGURA 11 – Conteúdo do arquivo mensagem.txt exibido na tela. 58 Apesar do objeto XMLHttpRequest possuir amplo suporte por parte dos navegadores, não se trata de um padrão W3C como já mencionado anteriormente. A especificação W3C que trata dessa funcionalidade é o DOM Level 3 Load and Save Specification, que ainda não foi implementado por nenhum navegador. De acordo com Asleson e Schutta (2006) essa especificação foi criada com o objetivo de ser uma maneira de alterar o conteúdo do documento DOM usando conteúdo XML. Ambas as tecnologias são os assuntos a serem abordados no próximo capítulo. 59 5. DOCUMENT OBJECT MODEL E XML Segundo a definição de Asleson e Schutta (2006) o DOM é uma especificação da W3C para uma maneira de se acessar e modificar o conteúdo e estrutura de um documento de maneira independente de plataforma e linguagem de programação utilizada. Trata-se, como explica Jacobs (2006), de uma application programming interface (API) para XML cujo objetivo é permitir a uma aplicação manipular um documento XML, ler dados, adicionar novos nós e editar o conteúdo existente. Pelo fato de estar diretamente relacionado ao XML antes de abordar os conceitos relativos ao DOM é necessário primeiramente compreender a estrutura do documento XML. 5.1 Documento XML O Extensible Markup Language (XML) surgiu em 1998 e é baseado no SGML, uma linguagem cujo propósito é definir a sintaxe de linguagens de marcação para representar dados usando tags. Jacobs (2006) diz que o ponto mais importante sobre o XML é que não se trata de uma linguagem em si. Na verdade, trata-se de uma metalinguagem usada para construir outras linguagens e vocabulários. Um exemplo de linguagem XML é o XHTML, que possui um grupo padrão de tags que devem ser usadas de uma maneira específica. XML é uma recomendação W3C e é uma poderosa abordagem para o gerenciamento de informações. Através de documentos XML é possível compartilhar dados. A W3C definiu uma série de objetivos para o XML, dentre os quais pode-se destacar: – Deve ser fácil escrever programas que processam documentos XML; – Documentos XML devem ser legíveis para humanos e razoavelmente claros; – Documentos XML devem ser fáceis de criar. É possível notar que a W3C deu ao XML dois alvos: humanos e processadores XML. Um processador XML ou analisador (parser) é um pacote de software que processa um documento XML. Processadores identificam o conteúdo de um documento XML, lêem, escrevem, mudam o documento ou criam um novo do início. O objetivo é abrir o mercado para os processadores XML fazendo com que sejam simples de serem desenvolvidos. Regras de construção estritas significam que menos processamento é necessário. Além disso, mantendo os documentos legíveis por humanos permite-se que os dados sejam acessados sem grande dificuldade, facilitando a construção e a depuração (debug) de aplicações. Um efeito colateral é que documentos XML podem ser extensos e descrever dados usando XML pode ser um processo mais longo do que seria utilizando outros métodos. 60 A sintaxe do XML baseia-se no uso de tags para marcação de texto. O uso de tags já foi visto na abordagem da linguagem XHTML, a diferença é que no XHTML as tags possuem um significado pré definido (<p> é um parágrafo, por exemplo), enquanto que no XML é possível construir tags próprias. Uma grande vantagem do XML é que as tags podem descrevem seu conteúdo (como em <cor>Azul</cor>). Os documentos XML possuem certos critérios para serem corretamente formados: – As linguagens XML são sensíveis à caixa (case sensitive), ou seja, a tag <nome> é diferente de <Nome> ou <NOME>. – Os nomes em XML não podem começar com número: deve ser uma letra ou sublinhado (underscore). Os caracteres restantes podem ser qualquer um, com exceção do espaço. – Todas as tags precisam ter uma tag de fechamento equivalente, e caso não exista conteúdo entre duas tags de abertura e fechamento pode-se utilizar uma única tag com uma barra ao final de seu nome (<livro/>, por exemplo). – Atributos sempre devem possuir aspas envolvendo seus valores, podendo ser tanto aspas simples quanto duplas. Exemplo: <livro isbn=”1020304050”>. <?xml version="1.0" encoding="UTF-8"?> <!-- Este documento XML contém os livros do acervo de uma biblioteca --> <acervo> <livro isbn="1010101010"> <titulo>Dom Casmurro</titulo> <autor>Machado de Assis</autor> <anoPublicacao>1900</anoPublicacao> </livro> <livro isbn="2020202020"> <titulo>O Ateneu</titulo> <autor>Raul Pompéia</autor> <anoPublicacao>1888</anoPublicacao> </livro> <livro isbn="3030303030"> <titulo>O Cortiço</titulo> <autor>Aluízio Azevedo</autor> <anoPublicacao>1890</anoPublicacao> </livro> </acervo> CÓDIGO 19 – Documento XML representado acervo de biblioteca. Todo documento XML é dividido em duas partes: o prolog e o elemento raiz (também chamado de document element). O prolog aparece no topo do documento XML. No código 19, o prolog contém uma declaração XML que define para o documento a versão 1.0 e a codificação UTF-8. Embora seja opcional, é sempre uma boa idéia incluir a declaração XML para informar que o documento apresenta conteúdo XML, além de também prover a 61 processadores informações adicionais como o tipo de codificação de caractere (neste caso UTF-8). A declaração XML sempre deve aparecer na primeira linha do documento. O prolog também pode conter instruções de processamento, cuja finalidade é passar informações para aplicações que estejam processando o documento XML. O processador XML não processa essa instrução, ao invés disso ele apenas repassa para a aplicação, sem alterações. Um uso comum de instruções de processamento é o seguinte: <?xml-stylesheet type="text/css" href="folha_de_estilo.css"?> Essa instrução especifica a folha de estilo folha_de_estilo.css a ser aplicada ao documento XML. Comentários, da mesma forma que HTML/XHTML, começam com <!-- e terminam com --> e podem ser inseridos em praticamente qualquer lugar do documento. Apenas não podem ser inseridos dentro de nomes de tag. O código 19 contém um comentário no prolog do documento. O prolog também pode conter DTDs e esquemas XML, que provêm regras sobre quais elementos e atributos podem aparecer dentro do documento XML. Em outras palavras, eles especificam quais elementos e atributos são válidos e quais são necessários ou opcionais. Uma referência externa a um DTD poderia ser inserida no documento do código 19 da seguinte forma: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE acervo SYSTEM "biblioteca.dtd"> <!-- Este documento XML contém os livros do acervo de uma biblioteca --> A segunda parte do documento XML, o elemento raiz, é onde são armazenados os dados do documento. Ele contém todos os outros elementos, atributos, textos e CDATA (tipo de seção a ser vista adiante), além de poder também incluir entidades e comentários. Um elemento é o conjunto da tag de abertura e de fechamento, além do conteúdo entre eles. O conteúdo pode ser texto e elementos filhos. A tag de abertura do elemento também pode conter atributos, e comentários podem ser inseridos dentro de elementos. Ainda utilizando como referência o documento do código 19: <livro isbn="1010101010"> <titulo>Dom Casmurro</titulo> <autor>Machado de Assis</autor> <anoPublicacao>1900</anoPublicacao> </livro> A tag de abertura <livro> contém um atributo isbn e inclui três outros elementos: <titulo>, <autor> e <anoPublicacao>. Cada um desses elementos contêm texto. 62 Atributos são uma outra maneira de prover informação em documentos XML. Através de sua inserção na tag de abertura de um elemento, eles normalmente provêm informações adicionais sobre o elemento que modificam. Não há limite ao número de atributos que podem aparecer em um elemento. Eles consistem de pares de nome/valor, com o valor envolvido por aspas duplas ou simples. Dois usos comuns de atributos são transmitir informações de formatação e indicar o uso de um formato específico ou codificação. Por exemplo, poderia-se transmitir uma data como: <data formato="ddmmyyyy">20102007</data> Todo texto em um documento XML está contido dentro de tags de abertura e de fechamento e, a não ser que seja marcado como CDATA, será tratado como se fosse XML e processado dessa maneira. Isso significa que um sinal de maior será tratado como se fosse parte de uma tag XML. Se for necessário utilizar caracteres reservados no texto, é necessário reescrevê-los como entidades de caractere (character entities). As entidades de caractere são símbolos que representam um único caractere. Os caracteres considerados reservados e suas entidades correspondentes são descritos na tabela 2, e o código 20 apresenta um exemplo de sua utilização: Caractere Entidade & & ' ' > > < < " " TABELA 2 – Entidades de caractere usadas em documentos XML. <!-- A tag abaixo invalida o documento pois contém um caracter reservado no texto --> <expressao_invalida>30 < 45</expressao_invalida> <!-- A tag a seguir é válida, utiliza uma entidade de caractere --> <expressao_valida>30 < 45</expressao_valida> CÓDIGO 20 – Exemplo do emprego de uma entidade de caractere. Também é possível incluir outros caracteres como entidades de caractere usando números Unicode ou hexadecimais. Por exemplo, é possível codificar o símbolo de copyright © como © ou ©. O número entre &# e o ponto-e-vírgula é o código Unicode do caractere a ser exibido. Se o código for em hexadecimal, então ele é prefixado com o caractere x. 63 Além da utilização de entidades de caractere, também é possível inserir caracteres reservados no texto usando CDATA. Seções CDATA permitem que blocos de texto sejam marcados para que não sejam processados como XML: <questao><!CDATA[Demonstre porque 5 < 10]]</questao> A seção CDATA inicia com <!CDATA[ e termina com ]], e os dados ficam contidos entre o colchete de abertura e o de fechamento. Seções CDATA são úteis para inserir código embutido, como JavaScript, e para adicionar conteúdo que não requer processamento. Por exemplo, uma aplicação que lê dados de um banco de dados e os marca em XML poderia inserir todo o conteúdo em seções CDATA para evitar a necessidade de processar caracteres reservados explicitamente. De acordo com Jacobs (2006) a recomendação XML assume que um documento XML deve ser processado de uma maneira particular: um processador XML deve passar o conteúdo e a estrutura do documento XML para uma aplicação. A biblioteca MSXML da Microsoft, por exemplo, disponibiliza juntamente com o objeto XMLHttpRequest visto anteriormente, um parser XML. Existem dois tipos de processamento XML: baseado em evento (event-based) e baseado em árvore (tree-based). Os analisadores (parsers) baseados em evento são conhecidos como analisadores Simple API for XML (SAX). Zakas (2005) explica como funcionam os analisadores SAX: eles começam a partir do início do documento e analisam o código navegando através dele de maneira direta, disparando eventos sempre que encontram uma tag de abertura, uma tag de fechamento, atributo, texto, ou outra sintaxe XML. O desenvolvedor então define o que fazer quando cada um desses eventos ocorre. Analisadores SAX são leves e rápidos porque apenas analisam o texto e continuam seu caminho em direção ao final do documento. Sua principal desvantagem é que não é possível parar, voltar, ou acessar partes específicas da estrutura XML sem iniciar novamente a partir do início do documento. Esse tipo de analisador funciona bem com linguagens que possuem boas propriedades de manipulação de eventos. SAX, por exemplo, é bastante utilizado com Java, mas é menos adequado para as linguagens de scripting freqüentemente utilizadas na web. Os analisadores baseados em árvore, por sua vez, são conhecidos como analisadores DOM. O DOM é uma API baseada em árvore para XML. Seu foco principal não é apenas analisar código XML, mas representar esse código usando uma série de objetos interligados que podem ser modificados e acessados diretamente sem a necessidade de re-analisar o código. Usando o DOM, o código é analisado uma vez para criar uma árvore modelo, e então o código original não é mais necessário. Embora o DOM seja mais lento que o SAX e 64 requeira mais sobrecarga porque cria muitos objetos, ele é, devido a sua facilidade de uso, o método preferido para JavaScript e navegadores web. 5.2 Funcionamento do DOM A definição exata da W3C para o DOM é: O Document Object Model é uma interface neutra de plataforma e linguagem que permitirá a programas e scripts dinamicamente acessar e atualizar o conteúdo, estrutura, e estilo de documentos. O documento pode ser adicionalmente processado, e os resultados desse processamento podem ser incorporados de volta à página atual. (W3C apud Asleson e Schutta, 2006 p. 43). A recomendação da W3C para o DOM prevê três níveis de suporte, numerados de 1 a 3, respectivamente. Quanto maior o nível DOM, mais recursos suportados. Zakas (2005) define os níveis: o DOM Level 1 consiste de duas partes: o núcleo do DOM, que provê uma maneira de mapear a estrutura de um documento baseado em XML, e o DOM HTML, que estende o núcleo do DOM adicionando objetos e métodos específicos do HTML. O DOM Level 2 adicionou suporte a eventos do mouse e da interface do usuário e métodos para realizar iterações em um documento DOM, suporte a CSS através de interfaces de objetos e suporte a XML namespaces1. O DOM Level 3 introduziu métodos para salvar e carregar documentos de maneira uniforme (através do já citado DOM Level 3 Load and Save Specification) bem como métodos para validar um documento. Este nível também estende o núcleo do DOM para suportar todo o XML 1.0, incluindo XML Infoset, XPath e XML Base. Por parte dos navegadores web, o que apresenta o melhor nível de suporte ao DOM é o Mozilla, enquanto que o Internet Explorer é o que apresenta o menor nível. A tabela 3 contém o suporte ao DOM por parte dos principais navegadores: 1 XML namespaces provêm uma maneira de classificar nomes de elementos e atributos usados em documentos XML. Um namespace identifica nomes de maneira única evitando ambigüidade. 65 Navegador Conformidade com o DOM Netscape Navigator 1.0 - 4.x - Netscape 6.0+ (Mozilla 0.6.0+) Nível 1, Nível 2, Nível 3 (parcial) Internet Explorer 2.0 - 4.x - Internet Explorer 5.0 Nível 1 (mínimo) Internet Explorer 5.5+ Nível 1 (quase completo) Opera 1.0 - 6.0 - Opera 7.0+ Nível 1 (quase completo), Nível 2 (parcial) Safari 1.0+ / Konqueror ~2.0+ Nível 1 TABELA 3 – Suporte ao DOM pelos principais navegadores. Um ponto importante destacado por Asleson e Schutta (2006) é que o DOM pode ser facilmente confudido com JavaScript. O DOM é uma API que provê uma representação estrutural do documento e define como o documento é acessado, enquanto que JavaScript é uma linguagem usada para acessar e manipular o DOM. Sem o DOM, JavaScript não teria qualquer noção de páginas web e os elementos que compõem as páginas. Cada elemento em um documento é parte do DOM, que torna as propriedades e métodos dos elementos disponíveis ao JavaScript. Como já mencionado, o DOM é uma API baseada em árvore (tree-based). Isso significa que ele representa o documento XML como uma árvore (ou hierarquia) de nós. Considerando o documento XML do código 21, sua correspondente árvore de nós representada pelo DOM é a exibida pela figura 12: <?xml version="1.0"?> <alunos> <!-- Único aluno --> <aluno> <nome>João Silva</nome> <idade>15</idade> <comentarios><![CDATA[ Aluno aplicado em sala. ]]></comentarios> </aluno> </alunos> CÓDIGO 21 – Documento XML. 66 FIGURA 12 – Árvore de nós representando documento XML. Na figura 12, cada retângulo representa um nó na árvore do documento DOM, com o texto em negrito indicando o tipo do nó e o texto comum indicando o conteúdo do nó. O nó de comentário e o nó <aluno> são considerados nós filhos de <alunos>, pois aparecem imediatamente abaixo dele. Portanto, <alunos> é considerado nó pai de ambos os nós <aluno> e de comentário. Similarmente, <nome>, <idade>, e <comentarios> são todos considerados nós filhos de <aluno> e também considerados irmãos (siblings) um do outro, pois estão no mesmo nível na árvore DOM e possuem o mesmo nó pai. O nó document é considerado o ancestral de todos os nós do documento. Zakas (2005) relaciona os tipos de nó definidos pelo DOM: – Document: o nó de mais alto nível ao qual todos os outros nós estão anexados; – DocumentType: a representação em objeto de uma referência DTD; não pode conter nós filhos; – DocumentFragment: pode ser usado da mesma maneira que Document para manter outros nós; – Element: representa o conteúdo das tags de abertura e de fechamento, como em <tag></tag>. É o único tipo de nó que pode conter atributos bem como nós filhos; – Attr: representa um par nome-valor de atributo. Esse tipo de nó não pode ter nós filhos; – Text: representa o texto contido entre uma tag de abertura e uma de fechamento ou dentro de uma seção CDATA. Não pode conter nós filhos; – CDATASection: a representação em objeto de <![CDATA[ ]]>. Esse tipo de nó só pode conter nós texto como nós filhos; 67 – Entity: representa uma definição de entidade em um DTD. Não pode conter nós filhos; – EntityReference: representa uma entidade de referência (ou entidade de caractere), como ". Este tipo de nó não pode ter nós filhos; – ProcessingInstruction: representa uma instrução de processamento. Não pode conter nós filhos; – Comment: representa um comentário. Não pode conter nós filhos; – Notation: representa notação definida em um DTD. Raramente utilizado. Além dos tipos de nó listados, o DOM também define várias interfaces. As principais são Document, Node, NodeList e NamedNodeMap. A interface Document representa o documento inteiro e é a raiz da árvore deste. Essa interface contém métodos para a criação de novos objetos que podem ser usados para adicionar novos elementos, nós de texto, e atributos usando código. A interface contém os seguintes membros: – documentElement: provê acesso direto ao elemento raiz do documento XML. Em um documento XHTML, este é o elemento <html>; – getElementsByTagName(nome_tag): este método retorna uma coleção de elementos do tipo NodeList com todos os elementos chamados nome_tag; – createElement(nome_da_tag): método utilizado para criar um elemento do tipo Element. O método cria um elemento com o nome de tag especificado: oDocument.createElement("nome_tag"); Quando esse método cria um novo elemento, este ainda não possui uma posição na árvore do documento. Ainda é necessário adicioná-lo, usando o método appendChild(): oDocument.documentElement.appendChild(Document.createElement("nome_tag")); – createTextNode(valor): cria nós de texto contendo “valor”, passado como argumento. Isso é equivalente a adicionar texto dentro de um elemento. O código abaixo cria um elemento <nome>João</nome>: oElement = oDocument.createElement("nome"); oElement.appendChild(oDocument.createTextNode("João")); oDocument.documentElement.appendChild(oElement); – createAttribute(nome_atr): pode-se utilizar esse método para criar objetos do tipo Attr (atributo). O valor de um atributo aparece em um nó de texto dentro deste atributo, então é possível utilizar uma abordagem similar à usada para adicionar um valor para um Element. É possível também utilizar a propriedade value para definir o valor do nó texto em um atributo: 68 oAttribute = oDocument.createAttribute("ID"); oAttribute.value = "4"; oNamedNodeMap = oDocument.documentElement.attributes; oNamedNodeMap.setNamedItem(oAttribute); Este código cria um atributo com o valor 4, e então o insere na coleção de atributos de um elemento através da chamada ao método setNamedItem() de um NamedNodeMap, que será abordado mais adiante. Document possui também os métodos para criar os demais tipos de nó: – createCDATASection(); – createComment(); – createDocumentFragment(); – createEntityReference(); – createProcessingInstruction(). A interface Node representa um único nó na árvore do documento. É o bloco de construção fundamental na representação de dados XML. Ela define uma série de propriedades e métodos que todos os tipos de nós contêm. A figura 13, baseada em Jacobs (2006, p. 231), demonstra a relação entre as principais propriedades da interface: FIGURA 13 – Relação entre as principais propriedades da interface Node. – attributes: essa propriedade retorna um NamedNodeMap que contém todos os atributos de um nó Element. Para outros tipos de nó, essa propriedade retorna null; 69 – parentNode: propriedade que retorna o pai do nó corrente. Nós sem pais retornam null. O código a seguir procura o pai do primeiro elemento <titulo>: oDocument.getElementsByTagName('titulo')[0].parentNode; – childNodes: retorna um NodeList que contém todos os nós filhos do nó selecionado. Os tipos de nó de podem conter filhos são Attr, Document, DocumentFragment, Element, Entity e EntityReference. Um texto dentro de um atributo é considerado um nó filho deste atributo; – firstChild e lastChild: a propriedade firstChild retorna o primeiro nó (tipo Node) da coleção childNodes do nó corrente enquanto que lastChild retorna o último: oNode = oDocument.documentElement.firstChild; – previousSibling e nextSibling: essas propriedades retornam respectivamente o nó anterior e o próximo nó que compartilham o mesmo pai que o nó corrente; – nodeName: propriedade que retorna uma string contendo o nome do nó corrente; – nodeValue: retorna o conteúdo do nó corrente. Para um elemento é null, mas para um atributo ou um nó texto, a propriedade retorna o valor do atributo ou o conteúdo do texto. O exemplo a seguir busca o texto contido no primeiro elemento <titulo>: oDocument.getElementsByTagName('titulo')[0].firstChild.nodeValue; – nodeType: essa propriedade fornece informação sobre o tipo do nó corrente. Cada nó tem um valor inteiro mapeado que vai de 1 a 12. Esses valores podem ser acessados também através de constantes Node, como por exemplo Node.ELEMENT_NODE (valor 1) ou Node.TEXT_NODE (valor 3); – hasChildNodes(): esse método retorna um valor booleano indicando se o nó corrente possui nós filhos; – appendChild(novo_filho): adiciona um novo filho ao fim da lista de nós filhos do nó corrente. É preciso criar o nó antes de adicioná-lo: oNewNode = oDocument.createElement("titulo"); oDocument.documentElement.appendChild(oNewNode); – cloneNode(profundidade): esse método clona o nó existente, copiando todos os seus atributos e valores. Possui o parâmetro boleano profundidade que determina se a clonagem deve ser recursiva; – insertBefore(novo_filho, filho_ref): insere um novo nó filho antes de um nó filho existente. Se filho_ref é null, o nó filho é inserido como o último. Se o nó novo já existe na árvore, o método o remove de sua posição original: 70 var oOldNode = oDocument.getElementsByTagName('titulo')[0]; oNewNode = oDocument.createElement('titulo'); oDocument.documentElement.insertBefore(oNewNode, oOldNode); – removeChild(filho): método que remove o parâmetro “filho” da coleção childNodes do nó corrente. Retorna uma refêrencia ao nó removido; – replaceChild(novo_filho, filho_antigo): esse método substitui um nó filho do nó corrente por um novo filho. O método retorna o nó substituído. O código a seguir cria um novo nó e usa replaceChild para substituir o último elemento filho: oNewNode = oDocument.createElement('titulo'); oRootNode = oDocument.documentElement; oOldNode = oRootNode.replaceChild(oRootNode.lastChild, oNewNode); É possível notar que as interfaces Document e Node permitem que nós sejam criados, adicionados, removidos ou substituídos. Essas funcionalidades tornam o DOM verdadeiramente dinâmico. A interface NodeList lida com coleções ordenadas de nós. Cada nó na coleção é indexado, iniciando em 0. Como visto anteriormente, a propriedade childNodes retorna um NodeList. Essa interface possui a propriedade length, que indica o tamanho do NodeList, e o método item(indice), o qual recebe como argumento um índice e retorna o nó correspondente no NodeList. O exemplo abaixo usa um loop for para realizar uma iteração através da coleção childNodes de documentElement e exibe um alerta mostrando o nome de cada nó da coleção: for(var i=0; i < oDocument.documentElement.childNodes.length; i++) { alert(oDocument.documentElement.childNodes.item(i).nodeName); } A última interface, NamedNodeMap, representa uma coleção de nós que podem ser acessados por nome ou índice. A coleção não é mantida em nenhuma ordem particular, e é possível usar a interface para adicionar e remover nós da coleção. NamedNodeMap pode ser retornado para coleções do tipo Entity ou Notation, mas é comumente associado à coleção de atributos de um nó. A propriedade attributes de um nó do tipo Element é um NamedNodeMap. A interface apresenta os mesmos membros item() e length de NodeList, além dos seguintes: – getNamedItem(nome_no): busca um nó por nome usando como parâmetro de busca nome_no; – removeNamedItem(nome_no): esse método usa o argumento nome_no para determinar o nó a ser removido; – setNamedItem(novo_no): recebe um Node como parâmetro e o adiciona à coleção: 71 var idAttr = oDocument.documentElement.firstChild.attributes.removeNamedItem("id"); oDocument.documentElement.lastChild.attributes.setNamedItem(idAttr); O código anterior remove o atributo id do primeiro filho e o adiciona à coleção attributes do último elemento filho. Quando usado para representar atributos, cada nó de um NamedNodeMap é um nó do tipo Attr, o qual sua propriedade nodeName contém o nome do atributo e nodeValue o seu valor. O atributo id do exemplo anterior pode ter seu valor alterado através da atribuição de um novo valor à propriedade nodeValue: oDocument.documentElement.lastChild.getNamedItem("id").nodeValue = "novoid"; Nós Attr também possuem uma propriedade value que é exatamente igual a nodeValue, bem como uma propriedade name igual a nodeName. De acordo com Zakas (2005) existem três métodos adicionais que auxiliam na designação de atributos: – getAttribute(nome): é o mesmo que attributes.getNamedItem(nome).nodeValue; – setAttribute(nome, novo_valor): equivalente a attributes.getNamedItem(nome).nodeValue = novo_valor; – removeAttribute(nome): equivalente a attributes.removeNamedItem(nome). Esses métodos facilitam a manipulação de atributos, pois escondem os nós Attr e permitem que o código se torne menor. Junto com o desenvolvimento do DOM XML, a W3C ao mesmo tempo desenvolveu um DOM mais específico ao XHTML (e HTML). Esse DOM define um HTMLDocument e HTMLElement como base da implementação e, com exceção de um pequeno grupo de elementos, cada elemento HTML é representado pelo seu próprio tipo HTMLElement (HTMLDivElement, por exemplo, representa <div>). É através desse DOM que a manipulação da página web pode ser realizada com JavaScript, permitindo a alteração da interface do usuário na abordagem Ajax. A criação do DOM HTML foi possível pois qualquer linguagem baseada em XML, como XHTML, pode utilizar o núcleo do DOM por se tratar tecnicamente de XML. As propriedades e métodos do núcleo do DOM (core DOM) são genéricas, feitas para funcionar com qualquer documento XML em qualquer situação. O HTMLDocument, que é a representação do Document do DOM XML e considerado a raiz da árvore do documento, é representado em JavaScript pelo objeto document1. 1 Como visto no capítulo 4, o objeto document também é considerado parte do BOM. 72 O DOM HTML apresenta propriedades e métodos adicionais específicos do HTML que tornam certas manipulações do DOM mais fáceis. Ele define, por exemplo, dois métodos para acessar nós de forma específica: – getElementsById(valor_id): esse método retorna um elemento com o atributo id contendo um valor específico. Em HTML, o atributo id é único: não podem haver dois elementos compartilhando o mesmo id. Este é sem dúvida o método mais rápido de se acessar um único nó específico na árvore do documento. Supondo o seguinte código HTML: <div id="div_1">Conteúdo do div</div> O elemento pode ser acessado da seguinte forma: var oDiv1 = document.getElementById("div_1"); – getElementsByName(nome): busca todos os elementos que possuem o atributo nome com o valor especificado. Considerando o seguinte trecho HTML: <p>Qual sua fruta preferida?</p> <input type="radio" name="radFruta" value="banana" />Banana <br/> <input type="radio" name="radFruta" value="pera" />Pêra <br/> <input type="radio" name="radFruta" value="laranja" />Laranja <br/> Todos os botões radio possuem o mesmo atributo name, pois deseja-se apenas um valor para esse campo. Para acessar esses elementos, pode-se utilizar o código: var oRadios = document.getElementsByName("radFruta"); alert(oRadios[0].getAttribute("value")); // exibe banana alert(oRadios[1].getAttribute("value")); // exibe pera O DOM HTML também permite que atributos sejam acessados como propriedades. Eles são adicionados aos elementos como propriedades, facilitando seu acesso. Supondo, por exemplo, o elemento: <img src="imagem.png" border="0" /> Para acessar e alterar os atributos src e border usando o núcleo do DOM, é necessário utilizar os métodos getAttribute() e setAttribute(), como visto anteriormente: alert(oImg.getAttribute("src")); alert(oImg.getAttribute("border")); oImg.setAttribute("src", "imagem_2.png"); oImg.setAttribute("border", "1"); 73 Porém, através do DOM HTML é possível acessar e alterar esses valores usando propriedades com o mesmo nome: alert(oImg.src); alert(oImg.border); oImg.src = "imagem_2.png"; oImg.border = "1"; A única exceção em que o nome do atributo não é o mesmo que o nome da propriedade é o atributo class, que especifica uma classe CSS a ser aplicada ao elemento. Isso ocorre porque class é uma palavra reservada em ECMAScript e não pode ser usada como nome de variável, propriedade ou função em JavaScript. Neste caso, o nome da propriedade é className. Utilizar propriedades para manipular atributos ao invés de usar getAttribute() e setAttribute() não traz vantagens reais, além do fato de diminuir o tamanho do código e torná-lo mais fácil de ser lido. Zakas (2005) ressalta que o navegador Internet Explorer tem problemas com o método setAttribute(): quando ele é usado, as mudanças nem sempre são refletidas corretamente, sendo melhor usar os atributos na forma de propriedades. O DOM HTML também apresenta recursos específicos para facilitar a tarefa de criação de tabelas, através da adição de uma série de propriedades e métodos aos elementos <table>, <tbody> e <tr>. Para o elemento <table>, os principais são: – tBodies: coleção de elementos <tbody>; – tFoot: aponta para o elemento <tfoot>, caso exista; – tHead: aponta para o elemento <thead>, caso exista; – rows: coleção de todas as linhas (rows) da tabela; – createTHead(): método que cria um elemento <thead> e o posiciona na tabela; – createTFoot(): cria um elemento <tfoot> e o posiciona na tabela; – deleteTHead(): remove o elemento <thead>; – deleteTFoot(): remove o elemento <tfoot>; – deleteRow(posição): remove a linha na posição especificada; – insertRow(posição): insere uma linha na coleção rows na posição especificada. Para o elemento <tbody> são adicionados os seguintes: – rows: coleção de linhas no elemento <tbody>; – deleteRow(posição): remove uma linha na posição especificada; – insertRow(posição): insere uma linha na coleção rows na posição especificada. Ao elemento <tr> são adicionados: – cells: coleção de células (cells) no elemento <tr>; 74 – deleteCell(posição): remove a célula na posição especificada; – insertCell(posição): insere uma célula na coleção cells na posição especificada; <table border="1" width="100%"> <tbody> <tr> <td>Célula 1,1</td> <td>Célula 2,1</td> </tr> <tr> <td>Célula 1,2</td> <td>Célula 2,2</td> </tr> </tbody> </table> CÓDIGO 22 – Tabela HTML. A implementação para a criação da tabela do código 22 utilizando os métodos específicos pode ser visto no código 23: // criar tabela var oTable = document.createElement("table"); oTable.setAttribute("border", "1"); oTable.setAttribute("width", "100%"); //criar o tbody var oTBody = document.createElement("tbody"); oTable.appendChild(oTBody); //criar primeira linha oTBody.insertRow(0); oTBody.rows[0].insertCell(0); oTBody.rows[0].cells[0].appendChild(document.createTextNode("Célula oTBody.rows[0].insertCell(1); oTBody.rows[0].cells[1].appendChild(document.createTextNode("Célula //criar segunda linha oTBody.insertRow(1); oTBody.rows[1].insertCell(0); oTBody.rows[1].cells[0].appendChild(document.createTextNode("Célula oTBody.rows[1].insertCell(1); oTBody.rows[1].cells[1].appendChild(document.createTextNode("Célula //adicionar a tabela ao corpo do documento document.body.appendChild(oTable); 1,1")); 2,1")); 1,2")); 2,2")); CÓDIGO 23 – Criação de tabela através do DOM HTML. A criação dos elementos <table> e <tbody> utilizou os métodos já conhecidos do núcleo do DOM, mas para a criação das duas linhas foram utilizados os métodos e propriedades específicos do DOM HTML para tabelas. Eles permitem que o código se torne mais lógico e legível, apesar de serem tecnicamente equivalentes aos métodos do núcleo do DOM. 75 Outro recurso bastante importante do DOM é o acesso ao estilo CSS dos elementos e às folhas de estilo CSS da página web, que permitem a mudança nos aspectos de apresentação dos elementos de forma dinâmica através de código JavaScript, sendo um recurso bastante empregado na técnica Ajax. O seguinte exemplo demonstra o acesso ao estilo CSS de um elemento: var oDiv = document.getElementById("div_1"); oDiv.style.border = "1px solid black"; oDiv.style.backgroundColor = "green"; Através do objeto style, é definido ao elemento <div> uma borda (style.border) de 1 pixel (1px), estilo sólido (solid) e de cor preta (black), além da cor de fundo (style.backgroundColor) verde (green). Supondo que as regras CSS anteriores tivessem sido definidas em uma folha de estilo como da forma a seguir: .div_1 { border: 1px solid black; background-color: green; } Seria possível acessá-las utilizando o código 24: <html> <head> <title>Acesso a folhas de estilo</title> <style type="text/css"> .div_1 { border: 1px solid black; background-color: green; } </style> <script language="javascript"> function pegaCorFundo() { var folhaEstilo = document.styleSheets[0].rules; // DOM if(!folhaEstilo) { folhaEstilo = document.styleSheets[0].cssRules; // Internet Explorer } alert(folhaEstilo[0].style.backgroundColor); alert(folhaEstilo[0].style.border); } </script> </head> <body> <div class="div_1"></div> <input type="button" value="Pegar cor de fundo" onclick="pegaCorFundo()"> </body> </html> CÓDIGO 24 – Acesso a folha de estilo CSS através do DOM. 76 No código 24, o usuário ao clicar no botão “Pegar cor de fundo” verá um aviso com o texto “green” (verde), que é a cor de fundo definida para a classe div_1. Para acessar esse valor, primeiramente é estabelecida uma referência à folha de estilo da página (document.styleSheets[0]) através da coleção document.styleSheets. Para acessar as regras individuais na folha de estilo especificada, existe uma diferença entre os navegadores: o DOM define para cada folha de estilo uma coleção chamada cssRules que contém todas as regras CSS da folha de estilo, enquanto que o IE define a mesma coleção, porém com o nome de rules. Cada uma das regras possui uma propriedade style, que é a mesma encontrada em elementos, como visto anteriormente. Portanto, para obter uma referência à regra style.backgroundColor, individual que por background-color sua vez através pode ser de style referenciado utiliza-se como document.styleSheets[0].cssRules[0].style.backgroundColor no caso do método para navegadores DOM ou document.styleSheets[0].rules[0].style.backgroundColor para Internet Explorer. O DOM ainda possui outros recursos, como os ranges que podem ser usados para selecionar uma seção de um documento independentemente de limites de nó, além de NodeIterator e TreeWalker (ambos partes do DOM Level 2, não suportados pelo navegador IE), que auxiliam tarefa de navegar através dos nós da árvore DOM. Os navegadores ainda disponibilizam também algumas extensões ao DOM não padronizadas, como as propriedades innerText, que permite acessar ou inserir texto entre uma tag de abertura e fechamento, e innerHTML, cuja função é a mesma porém permite a inserção de código HTML. No próximo item, serão vistos exemplos de utilização do DOM e XML dentro da abordagem Ajax. 5.3 DOM e XML na abordagem Ajax De acordo com Jacobs (2006) é possível que código do lado cliente utilize documentos XML como fonte de dados que podem ser trabalhados com JavaScript para gerar conteúdo HTML dinamicamente. Isso permite que a página web seja atualizada sem a necessidade de recarregá-la. A abordagem Ajax faz uso dessa possibilidade, empregando para isso o DOM e o XML. A função do XML é servir como formato para a representação de dados, enquanto que o DOM permite através de sua API o processamento do documento XML e a atualização do conteúdo HTML da página web de maneira dinâmica através do JavaScript. Na técnica Ajax, o XML pode ser empregado tanto nas requisições do cliente ao servidor quanto nas respostas deste ao cliente. McLaughlin (2006) porém sugere que na 77 maioria das vezes XML não deve ser usado em requisições do cliente ao servidor, pois a construção de uma requisição em XML não é tão simples quanto utilizar o tradicional texto plano e pares de nome/valor. Clientes podem enviar requisições com múltiplos valores usando pares de nome/valor facilmente, bastando adicionar o caractere & entre os sucessivos pares, como em cargo=gerente&salario=1500. Quando pares nome/valor são enviados, o navegador web que envia a requisição e a plataforma que hospeda o programa servidor cooperam para transformar esses pares em dados com os quais o programa pode trabalhar facilmente. Praticamente todas as tecnologias do lado servidor (server side) como PHP e Java servlets possuem vários métodos para acesso aos dados baseados em nome/valor, sendo portanto uma tarefa trivial. Além disso, XML não traz vantagens em relação ao texto plano, já que não há quase nada que possa ser enviando usando XML que não possa ser enviado utilizando texto com pares de nome/valor. Em relação às respostas retornadas ao cliente, McLaughlin (2006) explica que a recíproca não é verdadeira. O cliente não possui uma maneira fácil e padronizada de processar vários pares de nome/valor, mas possui para o XML através do uso do DOM para processar um documento XML recebido como resposta do servidor. Embora não seja indicado na maioria das vezes, pode ser necessário enviar XML para o servidor nos casos em que este apenas aceita requisições neste formato. Nessa situação, é necessário criar um novo documento XML no cliente para envio ao servidor. Da mesma forma que ocorre com o objeto XMLHttpRequest, existem duas maneiras: uma de acordo com o DOM e a outra encontrada no navegador Internet Explorer, como visto no código 25. var oXmlDoc = null; // cria documento XML em navegadores DOM if(document.implementation && document.implementation.createDocument) { oXmlDoc = document.implementation.createDocument("", "", null); } // cria documento no navegador Internet Explorer else if (window.ActiveXObject) { oXmlDoc = new ActiveXObject("Microsoft.XMLDOM"); } else { alert("Não foi possível criar documento XML."); } CÓDIGO 25 – Criação de documento XML em JavaScript. De maneira análoga ao objeto XMLHttpRequest, pode-se procurar instanciar a versão mais recente do objeto documento DOM no Internet Explorer utilizando um loop for e um vetor contendo todas as versões conhecidas. Uma vez criado, é possível adicionar conteúdo ao documento utilizando os métodos já vistos do núcleo DOM, ou mesmo carregando um arquivo XML através do método load(“nome_arquivo.xml”). O código 26 mostra uma 78 aplicação que envia uma requisição XML ao servidor para realizar um cadastro. Este então retorna ao cliente um documento XML contendo o código de resposta para a requisição: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Exemplo de requisição XML</title> <style type="text/css"> #divStatus { background-color: yellow; display: block; width: 220px; margin-top: 10px; } </style> <script type="text/javascript"> function cadastraUsuario() { var iNome = document.getElementById("inputNome").value; var iEmail = document.getElementById("inputEmail").value; if(iNome == "" || iEmail == "") { alert("Dados incompletos."); return; } // criar documento XML var docXml = criaDocumentoXML(); var xmlRaiz = docXml.createElement("requisicao"); var xmlNome = docXml.createElement("nome"); var xmlEmail = docXml.createElement("email"); xmlNome.appendChild(docXml.createTextNode(iNome)); xmlEmail.appendChild(docXml.createTextNode(iEmail)); xmlRaiz.appendChild(xmlNome); xmlRaiz.appendChild(xmlEmail); docXml.appendChild(xmlRaiz); // converter documento para string var xmlString = ""; if(window.XMLSerializer) { //conversão em navegadores DOM var serializer = new XMLSerializer(); xmlString = serializer.serializeToString(docXml,"text/xml"); } else if(window.ActiveXObject) { // conversão no navegador Internet Explorer xmlString = docXml.xml; } else { alert("Não foi possível realizar operação."); return; } realizaRequisicao(xmlString); } function criaDocumentoXML() { var oXmlDoc = null; // cria documento XML em navegadores DOM if(document.implementation && document.implementation.createDocument) { oXmlDoc = document.implementation.createDocument("", "", null); } // cria documento no navegador Internet Explorer else if (window.ActiveXObject) { oXmlDoc = new ActiveXObject("Microsoft.XmlDOM"); } 79 else { alert("Não foi possível criar documento XML."); } return oXmlDoc; } function criaObjetoXHR() { xmlhttp = null; if (window.XMLHttpRequest) { // navegadores Mozilla, Opera ou Safari xmlhttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { // navegador Internet Explorer var XmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'); for(var i=0; i < XmlHttpVersions.length && !xmlhttp; i++) { try { xmlhttp = new ActiveXObject(XmlHttpVersions[i]); } catch(e) { xmlhttp = null; } } } } function realizaRequisicao(dados) { criaObjetoXHR(); if(!xmlhttp) { alert ("Não foi possível realizar a operação."); return; } xmlhttp.onreadystatechange = processaResposta; xmlhttp.open("POST", "http://localhost/processa.php", true); xmlhttp.send(dados); } function processaResposta() { if(xmlhttp.readyState == 4) { var oDivStatus = document.getElementById("divStatus"); if(xmlhttp.status == 200) { try { var resposta = xmlhttp.responseXML; var statusResposta = resposta.getElementsByTagName("status")[0].firstChild; switch(statusResposta.nodeValue) { case "20": oDivStatus.firstChild.nodeValue = "Cadastro realizado."; break; case "10": oDivStatus.firstChild.nodeValue = "E-mail já existe."; break; default: oDivStatus.firstChild.nodeValue = "Erro desconhecido."; } 80 } catch(e) { document.body.removeChild(oDivStatus); alert("Ocorreu um erro no processamento da resposta."); } } else { document.body.removeChild(oDivStatus); alert("Ocorreu um erro no envio da requisição."); } setTimeout("document.body.removeChild(document.getElementById('divStatus'))", 3000); } else { var msgStatus = "Carregando ... status: "+xmlhttp.readyState; if(!document.getElementById("divStatus")) { var oDivStatus = document.createElement("div"); oDivStatus.setAttribute("id","divStatus"); oDivStatus.appendChild(document.createTextNode(msgStatus)); document.body.appendChild(oDivStatus); } else { document.getElementById("divStatus").firstChild.nodeValue = msgStatus; } } } // adiciona manipulador do evento onclick window.onload = function() { document.getElementById("inputButton").onclick = cadastraUsuario; } </script> </head> <body> <div> Nome: <input id="inputNome" type="text" value=""> E-mail: <input id="inputEmail" type="text" value=""> <input id="inputButton" type="button" value="Cadastrar"> </div> </body> </html> CÓDIGO 26 – Aplicação para cadastro de nome e e-mail. No código 26, primeiramente o usuário digita seu nome e e-mail e pressiona o botão “Cadastrar”. Em seguida, de acordo com o manipulador onclick definido para este botão (definido através de window.onload), a função cadastraUsuario() é disparada, que por sua vez verifica se os valores dos campos Nome e E-mail não são vazios (utilizando o método getElementById() do DOM HTML), e então aciona a função criaDocumentoXML(). Essa função cria um novo documento XML de acordo com o navegador em uso e retorna o objeto à função cadastraUsuario(). Esta usa os métodos do núcleo DOM para criar os nós (métodos createElement(), createTextNode() e appendChild()) e os anexa ao documento criado. O objeto é então convertido em texto (string) para que possa ser enviado na requisição ao servidor. Para essa operação também é necessário realizar uma verificação de objeto/funcionalidade, pois o navegador Internet Explorer executa a operação de maneira diferente dos navegadores DOM. Feita a conversão, a função realizaRequisicao() é acionada, recebendo como argumento a string do documento XML. Esta função cria o objeto 81 XMLHttpRequest através de criaObjetoXHR() (como já visto anteriormente no código 18 do capítulo 4) e faz uma requisição POST ao endereço http://localhost/processa.php, enviando o documento XML através do método send(). Quando send() é disparado, a função processaResposta(), definida como manipuladora do evento onreadystatechange, passa a atuar, e enquanto a requisição está sendo processada (enquanto readyState é diferente de 4), ela exibe na interface do usuário uma mensagem informando que a ação está em curso e qual é seu status atual. Isso é feito criando-se um elemento <div> e o adicionando à página (document.body.appendChild()). A função setAttribute() também é usada para designar um atributo id ao elemento, de maneira que ele possa incorporar as regras de estilo CSS definidas para este id e também para que possa ser localizado posteriormente pelo método getElementById(). No momento em que o processamento termina (readyState igual a 4), verifica-se o status HTTP da requisição (200 significa requisição bem sucedida) e então a resposta, que também é um documento XML, é processada. Esse documento contém uma tag <status> que contém o código de status da operação. Através do método do núcleo DOM getElementsByTagName(), o valor dessa tag é acessado e uma mensagem é exibida ao usuário (utilizando o <div> previamente criado) de acordo com o número de status encontrado (bloco switch-case). O documento XML de resposta é processado dentro de um bloco try-catch porque caso haja algum erro no XML enviado pelo servidor, uma exceção é disparada e o erro é tratado exibindo uma mensagem de aviso ao usuário. Por fim, utiliza-se o método do BOM do JavaScript setTimeout() para que a mensagem exibida ao usuário (elemento <div>) seja removida da página em três segundos. É importante lembrar que todas as operações são feitas de forma assíncrona, ou seja, em nenhum momento a página fica bloqueada para uso pelo usuário. A figura 14 exibe a aplicação sendo utilizada no momento em que a requisição está em andamento. FIGURA 14 – Aplicação realizando requisição XML. Embora seja um exemplo simples, a aplicação mostra os conceitos e a integração das várias tecnologias que compõem a abordagem Ajax. 82 6. PROTÓTIPO A utilização de grades de dados em páginas web sempre foi uma tarefa difícil de ser realizada devido a sua natureza tradicionalmente estática, sendo uma área em que aplicações web sempre apresentaram desvantagens em relação às aplicações desktop. A necessidade de um completo recarregamento da página ao atualizar células de um registro ou mudar a página da grade compromete a usabilidade da aplicação e inviabiliza seu uso para esse tipo de tarefa. Como já visto nesse estudo, a abordagem Ajax se propõe a tornar as aplicações web dinâmicas e interativas, através da troca de dados com o servidor de forma assíncrona e da atualização dinâmica da interface do usuário. Grades de dados apresentam uma demanda inerente por interatividade e usabilidade e necessitam de atualização dinâmica da interface, justamente os requisitos aos quais Ajax procura atender. Dessa maneira, isso torna uma aplicação web que disponibilize uma grade de dados utilizando Ajax um excelente exemplo de aplicação da abordagem e uma boa maneira de avaliar sua aplicabilidade para o fim a que se propõe. O protótipo desenvolvido, portanto, faz uso de uma grade de dados na forma de um cadastro de clientes. A implementação buscou atender aos seguintes requisitos: – o usuário deve ser capaz de interagir com a grade atualizando qualquer campo de um registro de maneira dinâmica, sem a necessidade de recarregar a página; – deve ser possível adicionar um novo registro, e para tanto a aplicação deve gerenciar a atualização da interface para disponibilizar os novos campos para inserção do cadastro e em seguida incorporar o novo registro aos demais já existentes; – o usuário deve ser capaz de navegar entre os registros utilizando as setas para cima e para baixo, como o faria em uma grade de uma aplicação desktop; – é necessária que a edição de um registro possa ser cancelada a qualquer momento através da tecla ESC ou de um clique do mouse fora da área de edição, retornando os dados alterados mas não salvos aos seus valores originais; – deve ser possível realizar uma busca por nome de cliente, e o resultado levar o usuário automaticamente aonde o registro se encontra na grade; – a aplicação deve permitir ao usuário personalizar configurações, sendo possível definir quantos registros serão exibidos por página e a aparência (look and feel) da interface. 83 Os requisitos descritos buscam aproximar as funcionalidades do protótipo às de uma aplicação desktop, procurando avaliar a efetividade da técnica Ajax. A interface disponibilizada pelo protótipo é a exibida na figura 15: FIGURA 15 – Interface do protótipo Ajax. 6.1 Funcionamento e estrutura A aplicação é composta por um conjunto de arquivos, com finalidades específicas e estruturados da seguinte maneira: – ajax/index.html: ponto de partida da aplicação, trata-se de uma página HTML contendo a estrutura do documento a ser exibido ao usuário. Ao término do carregamento do arquivo, a função JavaScript iniciar(), embutida no elemento body como manipuladora do evento onload, é disparada e dá início ao funcionamento do motor Ajax. 84 – ajax/proto.js: arquivo principal da aplicação, contém toda a lógica JavaScript responsável pelo funcionamento do protótipo. No momento que a função iniciar() é disparada, todos os manipuladores de evento são adicionados aos elementos do documento HTML e conforme o usuário dispara um determinado evento, uma função correspondente contida nesse arquivo é chamada para responder à ação realizada. – ajax/css/base.css: arquivo contendo as regras CSS que definem a aparência básica da interface. Conforme determinam os web standards, todas as definições de apresentação (CSS) encontram-se separadas das definições de estrutura (HTML). – ajax/css/seta.png: imagem contendo uma seta utilizada para indicar o registro sobre o qual o mouse se encontra. – ajax/css/temas/padrao.css: regras CSS que definem a aparência do tema Padrão. – ajax/css/temas/azul.css: regras CSS que definem a aparência do tema Azul. – ajax/css/temas/vermelho.css: regras CSS que definem a aparência do tema Vermelho. – cgi-bin/servidor.cgi: aplicação C++ que atua como um CGI responsável por responder às requisições da aplicação Ajax, retornando as respostas no formato de um documento XML a ser processado pelo cliente; – cgi-bin/banco.dat: arquivo utilizado pela aplicação CGI que representa o banco de dados contendo os registros dos clientes. No momento em que o documento HTML termina de ser carregado e a função iniciar() é executada, começa a funcionar o motor Ajax. O protótipo funciona baseado nesse motor que, de acordo com as ações que o usuário realiza, dispara um evento JavaScript que por sua vez executa a função definida como manipuladora do evento. Esse manipulador realiza, quando necessário, uma requisição ao servidor (aplicação CGI), processa a resposta deste e atualiza a interface da página de maneira a responder à ação do usuário. O processo de definição das funções manipuladoras é feito de maneira análoga ao trecho a seguir, o qual associa a função irPrimeiraPag() ao elemento oLinkNavPri, elemento este que representa o link "<< Primeira" usado para mover-se até a primeira página da grade. oLinkNavPri.onclick = function() { irPrimeiraPag(); }; As requisições feitas ao servidor são enviadas no formato de pares nome/valor e as respostas são recebidas na forma de um documento XML, seguindo as definições vistas no item 5.3 do capítulo 5. O trecho do código 27, extraído do arquivo proto.js, mostra como os dados da requisição são criados para solicitar o envio dos registros dos clientes: 85 function irPrimeiraPag() { Sessao.registroAtual = 0; var dadosReq = "ACAO=BUSCARCLIENTES®ISTROATUAL=1&QTDREG=" + Config.registrosPagina; Sessao.xmlhttpAux.funcaoAcao = atualizarTabela; realizaRequisicao(dadosReq, Config.appServidor); } CÓDIGO 27 – Criação dos pares nome/valor e envio de requisição. O código é referente à função responsável por buscar os registros pertencentes à primeira página da grade de dados. A requisição é composta da ação a ser realizada (ACAO=BUSCARCLIENTES), o registro inicial (REGISTROATUAL=1) e o registro final (QTDREG=Config.registrosPagina), sendo Config.registrosPagina a variável que define a quantidade de registros que são exibidos por página. A aplicação CGI do lado servidor, ao receber a requisição, acessa a base de dados e cria o documento XML de resposta, que é posteriormente processado pelo cliente através do DOM parser. O documento XML de resposta apresenta a seguinte estrutura: <?xml version='1.0' encoding='UTF-8'?> <resposta> <total>15</total> <cadastro> <cliente> <id>10</id> <nome>João da Silva</nome> <endereco>Rua do Cacique, 10</endereco> <telefone>3867-5119</telefone> <ativo>0</ativo> </cliente> </cadastro> </resposta> CÓDIGO 28 – Documento XML contendo resposta do servidor. A função responsável pela comunicação com o servidor é realizaRequisicao(), que define os parâmetros da requisição e a executa através do método send() do objeto XMLHttpRequest. Recebida a resposta, é necessário processar o documento XML recebido e atualizar a interface do usuário. No caso do código 27, a função responsável por essa tarefa é atualizarTabela(), definida através da propriedade funcaoAcao. Essa função recebe a estrutura DOM contendo o XML da resposta e a utiliza para atualizar a interface do usuário, redesenhando a grade com os novos dados recebidos. Todas as ações do motor Ajax que envolvem comunicação com o servidor seguem o fluxo descrito, com variações nas funções a serem utilizadas e dados a serem enviados na requisição. De maneira geral, 86 depois que o usuário dispara o evento, o motor Ajax é acionado, executando a função associada ao elemento e ao evento em questão, realizando quando necessário uma requisição ao servidor através do objeto XMLHttpRequest do JavaScript e atualizando a interface da aplicação através da alteração do DOM da página, respondendo à ação do usuário. É importante lembrar que a comunicação feita com o servidor é feita de forma assíncrona, não havendo bloqueio no uso da aplicação por parte do usuário. Para que o usuário esteja ciente de que a comunicação está em andamento, o protótipo sempre exibe uma mensagem de "Processando ..." que é removida ao término do processamento, como uma maneira de informar ao usuário que a resposta à sua ação está em andamento. A mensagem pode ser vista através da figura 16. FIGURA 16 – Protótipo exibindo aviso de resposta em andamento. 6.2 Recursos Um dos recursos que a aplicação disponibiliza ao usuário é a capacidade de editar registros e adicionar novos. O acesso à edição de um registro é feito clicando-se sobre um de seus campos. Nesse momento, os campos do registro tornam-se editáveis e a opção de salvar surge ao final da linha. O usuário pode editar os valores e submeter os dados clicando em "Salvar", ou cancelar a edição tanto pressionando a tecla ESC quanto mudando o foco para qualquer outro elemento da página (clicando em outro registro, por exemplo). A figura 17 exibe um campo habilitado para edição: 87 FIGURA 17 – Registro habilitado para edição. O usuário pode inclusive navegar entre os registros utilizando o teclado através das teclas para cima e para baixo, como faria em uma tabela de uma aplicação desktop. Isso é possível graças ao evento onkeydown, que captura a tecla pressionada e associa a ela um código (keyCode), como visto no capítulo 4. O trecho do código 29, extraído de uma declaração switch-case, demonstra como é implementado o recurso: // seta para cima case 38: { if(!alvoTr.previousSibling) { return; } novoAlvo = alvoTr.previousSibling.firstChild; cancelarEdicao(e); var eNovo = new Object(); eNovo.target = novoAlvo; novoAlvo.onclick(eNovo); break; } CÓDIGO 29 – Implementação da navegação pelo teclado. A função do código basicamente é identificar a tecla pressionada (38, número correspondente à seta para cima), definir o registro imediatamente acima como o novo alvo, cancelar a edição do registro atual e acionar a edição do outro registro. A adição de um novo cadastro é disponibilizada pelo botão "Cadastrar Novo". No momento em que o usuário o pressiona, a aplicação desloca-se para a última página da grade e insere uma nova linha em branco, para que o usuário entre com os novos dados. De maneira análoga à edição de um cadastro já existente, o usuário pode cancelar a operação através da tecla ESC ou mudando o foco da linha para outro elemento. Neste caso, a nova linha é automaticamente removida. Se o usuário selecionar "Salvar", a aplicação verifica se os valores são válidos (campos em branco não são permitidos) e envia o novo registro ao servidor, exibindo em seguida na tela uma mensagem informando ao usuário que a 88 operação foi bem sucedida. A figura 18 exibe a aplicação no momento do cadastro de um novo cliente, após o usuário tentar submeter valores em branco. FIGURA 18 – Usuário cadastrando novo registro. Sempre que necessário, avisos iguais ao ilustrado na figura 18 são exibidos ao usuário para informá-lo de que este está realizando uma ação inválida ou retornar uma mensagem de sucesso ou falha, em resposta a alguma operação. Os avisos são exibidos e removidos dentro de um determinado intervalo, recurso implementado através da utilização do método JavaScript setTimeout, que permite o agendamento de um código a ser executado depois de um intervalo definido, e da regra CSS visibility, que permite alterar a visibilidade de um dado elemento do documento. Na parte superior da grade de dados são exibidas informações referentes ao total de clientes cadastrados (canto superior esquerdo), página atual, número de páginas e registros em exibição (canto superior direito). Para navegação entre as páginas, existem na parte inferior direita da grade os links "<<Primeira" (muda para a primeira página), "< Anterior" (página anterior), "Próxima >" (próxima página) e "Última >>" (última página). Tais links são atualizados dinamicamente conforme a página em que o usuário se encontra, de maneira que caso o usuário esteja na primeira página os links "< Anterior" e "<< Primeira" estarão desabilitados. Esse comportamento pode ser visto através da figura 19: FIGURA 19 – Links para navegação das páginas. 89 Para auxiliar no processo de edição da grade, o protótipo disponibiliza outros recursos através das abas localizadas na parte inferior da tela. O conteúdo de cada uma das abas é exibido dinamicamente, conforme o usuário seleciona a aba desejada. Quando a aplicação é iniciada a aba que surge por padrão é "Procurar". Sua função é auxiliar o usuário no processo de busca de um determinado registro, permitindo a este realizar uma procura através do nome do cliente. O usuário digita o nome desejado e a aplicação retorna os resultados da busca. Se nenhum nome for encontrado, a aplicação exibe o aviso correspondente na parte superior da tela, de maneira semelhante ao visto na figura 18. Caso registros sejam encontrados, uma tabela com os registros correspondentes é exibida, e no momento em que o usuário pressiona o botão do mouse sobre o registro desejado a aplicação automaticamente muda a grade para a página correspondente e aciona o registro para edição. Essa operação pode ser vista na figura 20. FIGURA 20 – Registro sendo editado após busca através da Aba "Procurar". Depois de terminada a procura, o usuário pode fechar a tabela com os resultados com um clique em "Fechar", localizado no canto superior direito desta. 90 A segunda aba, "Configurações", disponibiliza três opções ao usuário. A primeira é a possibilidade de determinar a quantidade de registros a serem exibidos por página, num intervalo de 5 a 15. Conforme o usuário altera o número, a aplicação automaticamente atualiza a grade, alterando a quantidade de registros sendo exibidos para o número selecionado e recalculando o número total de páginas. A segunda opção da aba permite ao usuário selecionar o tema de sua preferência a ser adotado para a interface da aplicação. Alterar o tema faz com que a aparência (look and feel) da aplicação mude, utilizando por exemplo novas cores e fonte de letra. A figura 21 exibe as opções da aba "Configurações", com a grade configurada para exibir 6 registros por página e a interface utilizando o tema alternativo azul. FIGURA 21 – Aplicação usando tema azul e exibindo a aba "Configurações". A implementação do recurso de seleção de tema consiste em remover do DOM da página o elemento <link> referente ao arquivo CSS que contém o tema atual, e adicionar um novo <link> apontando para o arquivo CSS do novo tema. A implementação pode ser vista no código 30: 91 function mudarTema(nomeTema) { var oLink = document.createElement("link"); oLink.href = "css/temas/" + nomeTema; oLink.type = "text/css"; oLink.rel = "stylesheet"; var oHead = document.getElementsByTagName("head")[0]; oHead.removeChild(oHead.getElementsByTagName("link")[1]); oHead.appendChild(oLink); } CÓDIGO 30 – Função que implementa o recurso de mudança de tema. A última opção da aba permite ao usuário selecionar qual método HTML (GET ou POST) deseja utilizar na comunicação da aplicação com o servidor. No momento em que o usuário seleciona um método diferente, a aplicação automaticamente envia uma requisição ao servidor solicitando dados e muda a grade para a primeira página, como uma maneira de se testar o funcionamento do método selecionado. Caso o método não esteja funcional (por restrição do servidor de páginas, por exemplo), um aviso é exibido ao usuário informando-o da falha na comunicação, podendo o usuário retornar ao método anterior. No caso do método GET, é necessário evitar o armazenamento da resposta em cache por parte do navegador. Para tanto é adicionado ao final da string que contém os dados a serem enviados a data atual, de maneira que a URL sempre será diferente e o navegador nunca armazenará em cache a resposta. A implementação dessa funcionalidade pode ser vista no código 31: var dataAtual = new Date(); var stringData = dataAtual.getFullYear() + "" + dataAtual.getMonth() + "" + dataAtual.getDate() + "" + dataAtual.getDay() + "" + dataAtual.getHours() + "" + dataAtual.getSeconds() + "" + dataAtual.getMilliseconds(); Sessao.xmlhttp.open("GET",url+"?"+encodeURIComponent(dados)+ "&CONTROLE="+stringData); Sessao.xmlhttp.send(null); CÓDIGO 31 – Técnica para evitar armazenamento de resposta para GET. A última aba, "Sobre", não disponibiliza recursos adicionais, sendo apenas de caráter informativo. Ao ser selecionada ela exibe o nome do protótipo e o autor. 92 6.3 Resultados Como resultado da implementação do protótipo é possível notar a proximidade que este apresenta em relação às aplicações desktop. A possibilidade de navegar entre os registros através do teclado e recursos como a edição e criação de registros sem a necessidade de recarregamento, deslocamento entre as páginas da grade sem bloqueio da aplicação, e a possibilidade do usuário selecionar um tema para aparência da interface são recursos encontrados apenas em programas desktop, como planilhas de cálculo por exemplo. O processo de desenvolvimento do protótipo tornou possível perceber de maneira efetiva como as tecnologias empregadas se relacionam. A utilização de JavaScript na codificação da lógica da aplicação, juntamente com a manipulação da API DOM para a alteração da estrutura da página são os elementos fundamentais no funcionamento da aplicação. O uso de documentos XML na recepção de dados do servidor mostrou ser uma maneira eficaz e simples de manipulador dados, pois é um formato de fácil manuseio e através do DOM parser é possível manipular o documento da mesma maneira que se manipula os elementos da página web, visto que se trata da mesma API. O emprego do objeto XMLHttpRequest na comunicação com o servidor permite um eficiente controle sobre a operação, sendo possível identificar erros de comunicação e de resposta, além da possibilidade de informar ao usuário que a operação está em andamento, sempre de forma assíncrona sem comprometimento da usabilidade da aplicação por parte do usuário. O par HTML/CSS possibilita uma separação clara entre estrutura e apresentação, o que facilita o trabalho do desenvolvedor, e CSS em particular fornece um alto nível de controle sobre a aparência dos elementos tornando possível a alteração da aparência de toda a estrutura da página com um clique do mouse, como mostrado no funcionamento do protótipo. Em contrapartida, devido ao nível de controle e recursos que esse conjunto de tecnologias disponibiliza ao programador, as aplicações web feitas em Ajax apresentam uma codificação mais complexa do que as aplicações tradicionais, chegando a um nível de dificuldade próximo ao de aplicações desktop. Além disso, existe a questão da compatibilidade entre navegadores, que torna o esforço de se criar uma aplicação ainda maior, pois em determinados momentos é necessário criar código duplicado para a mesma funcionalidade, um para cada tipo de navegador. Após o estudo do modelo de funcionamento do Ajax, de suas tecnologias e em vista dos resultados provenientes da implementação do protótipo, no capítulo a seguir são definidas as conclusões sobre a utilização da técnica no desenvolvimento de aplicações web. 93 7. CONCLUSÕES No início deste estudo foi abordada a questão relativa à demanda que os usuários apresentam por interfaces que facilitem o uso do software, permitindo a eles comunicar o que deve ser feito de maneira eficiente e ágil. Em meio a este contexto surgem os conceitos de usabilidade e interatividade que, quando aplicados ao software, definem qual o nível de qualidade do meio de comunicação que este oferece ao usuário. Nesse aspecto, é clara a diferença que existe entre a interação do usuário com um editor de textos comum (aplicação desktop) e uma página web contendo um formulário de cadastro. Como visto anteriormente, aplicações desktop são ricas nas maneiras em que a interação pode ocorrer, enquanto aplicações web apresentam um paradigma requisição-resposta que compromete a qualidade de sua interface. Com o uso cada vez maior da Internet, a demanda por interatividade como a proporcionada pela aplicação desktop cresce e é preciso satisfazê-la. Ajax se propõe a atender tal necessidade, combinando uma série de recursos de várias tecnologias já existentes com um novo paradigma de funcionamento da aplicação web. Após a realização do estudo do modelo de funcionamento do Ajax e dos recursos disponíveis nas tecnologias que este utiliza, juntamente com os resultados provenientes da implementação do software protótipo, é possível concluir que esta abordagem é capaz de atender o objetivo a que se propõe. Como pôde ser constatado, através da experiência de uso do protótipo, Ajax torna a aplicação web muito mais dinâmica e coloca o nível de qualidade de sua interface bastante próximo ao nível das aplicações desktop. A utilização de um motor Ajax que capta as ações do usuário e responde a elas de forma contínua, sem a necessidade de recarregamento da interface, é o ponto fundamental da técnica. O motor Ajax é uma verdadeira aplicação responsável por gerenciar todo fluxo de funcionamento do programa. Isso significa que o navegador deixa de hospedar apenas conteúdo e passa a hospedar a aplicação em si enquanto o servidor passa a fornecer dados ao invés de conteúdo. A vantagem imediata é a diminuição do tráfego entre cliente e servidor, como pôde ser visto através do protótipo: o cliente envia pequenas requisições, e o servidor retorna apenas os dados necessários ao funcionamento da aplicação, ao invés de enviar toda a interface novamente a cada nova requisição, como no modelo tradicional. Além disso, a interação do usuário com a aplicação é mais contínua, já que a resposta consiste em atualizar apenas alguns aspectos da interface ao invés do processo completo. Apesar das várias vantagens que a adoção da técnica apresenta, Jacobs (2006) lembra que Ajax não é um substituto para os outros modelos de aplicações web. Em alguns casos Ajax pode não ser indicado, como por exemplo em situações em que é preciso carregar páginas inteiras. O ponto importante a ser ressaltado é que a abordagem deve ser utilizada para o fim a que se destina, ou seja, aplicações web que demandam maior 94 interatividade com o usuário. Nem todas as páginas web necessitam de um motor Ajax, o que significa que a técnica não deve ser adotada indistintamente. Existem ainda implementações que fazem uso de Ajax para funcionalidades especifícas dentro de uma página web conforme a necessidade, sem obrigatoriamente adotar a abordagem em todo o site. O emprego da técnica Ajax também apresenta desvantagens, tais como: – Botão "Voltar" (Back) do navegador: devido ao fato da aplicação Ajax realizar todas as ações na mesma página e as requisições feitas com o objeto XMLHttpRequest não serem gravadas no histórico do navegador, o botão "Voltar" (Back) deixa de produzir o mesmo resultado que as aplicações web tradicionais. Isso pode ser um ponto negativo para os usuários que estão familiarizados com a utilização do botão para navegar dentro da aplicação. Para contornar essa questão, existem implementações disponíveis que fazem o botão produzir o resultado desejado. – Bookmarks: como o endereço da página não muda durante a execução da aplicação, não é possível fazer bookmarks. – Segurança: sendo o código fonte da aplicação visível para o navegador, ele pode ser acessado por qualquer pessoa que pode tentar descobrir como a aplicação foi feita. Tendo em vista que as aplicações Ajax se encontram muito próximas das aplicações desktop, é natural que suas características também sejam semelhantes. Ou seja, da mesma maneira que uma aplicação desktop não apresenta um botão "Voltar" igual ao do navegador web e não disponibiliza bookmarks, o mesmo ocorre com a aplicação Ajax. Ainda assim, havendo a necessidade, Ajax possui os recursos necessários para que o desenvolvedor possa disponibilizar funcionalidades equivalentes. Como citado já existem implementações que corrigem o comportamento do botão "Voltar" e é possível criar mecanismos de salvamento de estado em substituição aos bookmarks. Com relação à segurança, uma vez que a aplicação cliente apenas envia requisições e quem efetivamente implementa a lógica de negócio é a aplicação do lado servidor, o fato do usuário poder acessar o código fonte da aplicação Ajax não representa um problema real de segurança. Uma pessoa que esteja visualizando as requisições enviadas por qualquer aplicação web a um servidor (interceptando o tráfego de rede, por exemplo) terá praticamente o mesmo nível de acesso a informações que uma pessoa acessando o código fonte desta aplicação. Além disso, o próprio modelo atual já apresenta essa característica. Ainda assim, existe controvérsia em relação ao tema segurança em Ajax. Alguns especialistas não vêem grandes problemas de segurança. Pascarello, por exemplo, referenciado em Frye (2006), afirma que a utilização do objeto XMLHttpRequest não é nada 95 mais do que uma submissão normal de um formulário igual ao de páginas web convencionais, e que as mesmas informações possíveis de serem visualizadas no objeto XHR também podem ser visualizadas no código fonte de qualquer página web. Em contrapartida, outros especialistas consideram que o emprego da abordagem torna os problemas de segurança maiores. Hoffman, referenciado em Hines (2006), afirma que “Aplicações Ajax possuem uma grande superfície de ataque, muito maior que as aplicações tradicionais”. Por estar fora do escopo deste trabalho, a questão não será abordada a fundo, mas apresenta um vasto campo para pesquisa e caracteriza-se como uma oportunidade a outros pesquisadores interessados em estudar o tema em trabalhos futuros. 7.1 Frameworks No processo de adoção da técnica Ajax existem ainda as questões relativas à compatibilidade entre navegadores e o aumento da complexidade do código. Apesar de Ajax empregar uma série de tecnologias baseadas em padrões W3C, muitas vezes ocorrem discrepâncias principalmente entre o funcionamento dos navegadores que seguem o padrão DOM e o navegador Internet Explorer. Esse fato pôde ser observado durante a implementação do protótipo deste trabalho e obriga o desenvolvedor a ter um esforço adicional para criar soluções que contemplem as diferenças entre os navegadores. Apesar de ser um ponto negativo, não é na verdade uma desvantagem em relação ao modelo tradicional, uma vez que este também utiliza as mesmas tecnologias. O que ocorre na verdade é que o problema se torna mais evidente na medida em que a complexidade do código da aplicação aumenta com o emprego da abordagem. Uma vez que a aplicação dispõe de um maior número de recursos e se aproxima da aplicação desktop, o mesmo ocorre com o código, que aumenta sua complexidade. Para facilitar o processo de geração de código Ajax, diminuindo sua complexidade e evitando os problemas relativos à compatibilidade de navegadores, é possível encontrar um grande número de frameworks Ajax disponíveis. A maioria é de código aberto (open source), mas também existem alguns proprietários. Os principais são: – Dojo: framework de código aberto e um dos mais antigos, seu objetivo é disponibilizar um kit de ferramentas enquanto foca em questões de usabilidade. Para utilizar o objeto XMLHttpRequest por exemplo, ao invés do desenvolvedor realizar toda a configuração do objeto basta realizar uma chamada ao método bind, definindo a URL a ser feita a requisição e o método que manipulará a resposta. Um destaque é o suporte aos botões "Voltar" (Back) e "Avançar" (Forward) do navegador, sendo possível definir uma função a ser chamada quando o usuário 96 pressiona um dos botões. Dojo também procura solucionar a questão dos bookmarks em aplicações Ajax disponibilizando uma flag chamada changeURL. – qooxdoo: também um framework de código aberto, disponiliza vários recursos encontrados em aplicações desktop como menus, tooltips, desenho de grades de dados e suporte a arrastar-e-soltar (drag and drop), possui boa documentação e seu ponto forte são os elementos sofisticados como os citados. – Sarissa: liberado sob a licença General Public License (GPL), este framework permitir trabalhar de forma independente de navegador oferecendo suporte a APIs XML e facilitando o trabalho com o objeto XMLHttpRequest, não sendo necessário realizar checagens no navegador, além de também oferecer suporte para trabalhar com o DOM. – Sajax: também sob código aberto, este framework permite a realização de chamadas a código do lado servidor diretamente a partir do JavaScript. Suporta várias linguagens como Perl, Python, Ruby e ASP. Também merece destaque o framework disponibilizado pela Google, empresa que tem feito uso intensivo da abordagem Ajax em seus produtos, como o GMail e o Google Maps. Trata-se de um framework que permite o desenvolvimento de aplicações Ajax utilizando a linguagem Java. De acordo com a descrição da própria Google (http://code.google.com/webtoolkit/overview.html, nov. 2007), com o Google Web Toolkit (GWT) "você pode desenvolver e depurar aplicações Ajax na linguagem Java usando as ferramentas de desenvolvimento Java de sua escolha. [...] o compilador GWT traduz sua aplicação Java para JavaScript e HTML em conformidade com o navegador." Os frameworks apresentam-se como uma alternativa bastante viável ao desenvolvimento de código Ajax sem que haja a necessidade de enfrentar as questões referentes à maior complexidade do código e à compatibilidade entre navegadores. Utilizando suas bibliotecas, o desenvolvedor não precisa se preocupar em checar as particularidades de implementação específicas de cada navegador e tem à sua disposição APIs prontas para a utilização de poderosos recursos da abordagem, sendo possível preocupar-se apenas com a funcionalidade específica de sua aplicação. 7.2 Considerações finais Como conclusão, pode-se definir a abordagem Ajax como uma alternativa indicada e viável de se superar o modelo estático tradicional da web com o objetivo de desenvolver aplicações com melhores recursos de usabilidade e interatividade. Observado o fato de ser 97 utilizada para o fim a que se destina, a técnica demonstra eficiência na criação de aplicações que atendam a demanda crescente dos usuários por maior interatividade na web e por uma experiência de utilização mais próxima da oferecida por aplicações desktop. Suas desvantagens não comprometem a adoção, na medida em que ela própria disponibiliza os recursos para que tais desvantagens sejam endereçadas. Implementações específicas podem solucionar as questões referentes ao botão "Voltar" do navegador e ao uso de bookmarks, enquanto que a variedade de frameworks disponíveis diminui a complexidade do código e elimina a necessidade de esforço adicional para solucionar problemas de incompatibilidade entre navegadores. Apesar de recente, Ajax tem sido cada vez mais empregado na web e sua adoção tende a crescer nos últimos anos, desenhando um panorama futuro de cada vez mais funcionalidades, antes exclusivas das aplicações desktop (como editores de textos e planilhas), migrando para a web. Exemplo disso é a empresa Google, que atualmente já disponibiliza seu próprio editor de textos e uma planilha de cálculo através da web, semelhantes aos aplicativos encontrados nas suítes de escritório existentes. A maneira como a Internet é vista e utilizada hoje deve mudar, e Ajax exerce um papel central nesse processo que deve tornar cada vez mais a web no meio de escolha por parte das empresas e desenvolvedores para a disponibilização de seus softwares ao consumo pelo usuário final. 98 8. REFERÊNCIAS BIBLIOGRÁFICAS ASLESON, R.; SCHUTTA, N. T. Foundations of Ajax. Berkeley, CA: Apress, 2006. CRANE, Dave et al. Ajax in Action. Greenwich, CT: Manning Publications Co., 2006. DARIE, Cristian et al. AJAX and PHP: building responsive web applications. Birmingham, UK: Packt Publishing, 2006. ECMA. Standard ECMA-262 – ECMAScript Language Specification, 3rd edition, December 1999. Disponível via URL em: http://www.ecmainternational.org/publications/standards/Ecma-262.htm. Acesso em: 7 de out. de 2007. FRYE, Colleen. Eric Pascarello dissects Ajax security vulnerabilities. Data de publicação: 07 de fev. de 2006. Disponível via URL em: http://searchsoa.techtarget.com/qna/0,289202,sid26_gci1164745,00.html. Acesso em: 15 de nov. de 2007. GARRET, Jesse James. Ajax: A New Approach to Web Applications. Data de publicação: 18 de fev. de 2005. Disponível via URL em: http://www.adaptivepath.com/publications/essays/archives/000385.php. Acesso em: 28 de mai. de 2007. GEHTLAND, J.; GALBRAITH B.; ALMAER D. Pragmatic Ajax: a Web 2.0 primer. [S.I.]: Pragmatic Bookshelf, 2006. GOODMAN, Danny. JavaScript Bible. 4th ed. New York, NY: Hungry Minds, 2001. GOOGLE. Product Overview - Google Web Toolkit. Disponível via URL em: http://code.google.com/webtoolkit/overview.html. Acesso em 10 de nov. de 2007. GRIFFITHS, Patrick. HTML dog: the best-practice guide to XHTML & CSS. Berkeley, CA: New Riders, 2007. HAINE, Paul. HTML Mastery: semantics, standards, and styling. Berkeley, CA: Friends of ED, 2006. HINES, Matt. Ajax Security Vulnerabilities Could Pose Serious Risk. FOXNews.com. Data de publicação: 04 de ago. de 2006. Disponível via URL em: http://www.foxnews.com/story/0,2933,207095,00.html. Acesso em: 15 de nov. de 2007. JACOBS, Sas. Beginning XML with DOM and Ajax - From Novice to Professional. New York, NY: Apress, 2006. KENNEDY, B.; MUSCIANO, C. HTML & XHTML: the Definitive Guide. 6th ed. [S.I.]: O'Reilly, 2006. 99 MCLAUGHLIN, Brett. Mastering Ajax, Part 7: Using XML in requests and responses. Disponível via URL em: http://www.ibm.com/developerworks/web/library/wa-ajaxintro7.html. Acesso em: 01 de nov. de 2007. YORK, Richard. Beginning CSS: cascading Style Sheets for Web Design. Indianapolis, IN: Wiley Publishing, 2005. W3C. About the World Wide Web Consortium (W3C). Disponível via URL em: http://www.w3.org/Consortium. Acesso em: 29 de mai. de 2007A. W3C. Serving XHTML 1.0. Disponível via URL em: http://www.w3.org/International/articles/serving-xhtml/Overview.en.php. Acesso em: 2 de jun. de 2007B. ZAKAS, N.C.; MCPEAK J.; FAWCETT J. Professional Ajax. Indianapolis, IN: Wiley Publishing, 2006. ZAKAS, Nicholas C. Professional JavaScript for Web Developers. Indianapolis, IN: Wiley Publishing, 2005.
Documentos relacionados
13. web 2.0 – a web social
Revista CEPPG – CESUC – Centro de Ensino Superior de Catalão , Ano XI, Nº 20, 1º Semestre/2009
Leia mais