terça-feira, 24 de junho de 2008

Cálculo de dias corridos entre duas datas em Javascript

Eu andei procurando na Internet como calcular diferença entre datas em Javascript ou, mais especificamente, como fazer o cálculo de dias entre duas datas. Pra variar, eu só achei soluções exdrúxulas. Então, como sempre, é melhor a gente fazer o nosso próprio código. Segue abaixo:

 1:  var a = new Date(2008, 8, 3);
2: var b = new Date(2008, 8, 15);
3: var c = b.getTime() - a.getTime();
4: var d = c / (24 * 60 * 60 * 24 * 1000); // 1 dia em milisegundos é 24 horas * 60 minutos * 60 segundo * 1000 milisegundos


Claro, se quiser achar a quantidade de horas, basta mudar o denominador do último cálculo para (60 * 60 * 1000), ou seja, 1 hora = (60 minutos * 60 segundos * 1000) milisegundos. E por aí vai.

quarta-feira, 9 de janeiro de 2008

Inconsistências entre os Browsers

Este tópico eu vou usar para catalogar as inconsistências existente entre os navegadores que atrapalham um desenvolvimento cross-browser. Vou listar o resultado nos browsers IE6.0, Opera 9.23 e Firefox 2.0.0.11.

1) Tag THEAD não aceita estilos OVERFLOW e HEIGHT

Exemplo:
231:<table>
232: <thead>
233: <tr><td>C.1</td><td>C.2</td></tr>
234: </thead>
235: <tbody style='height: 30px; overflow: auto;'>
236: <tr><td>1.1</td><td>1.2</td></tr>
237: <tr><td>2.1</td><td>2.2</td></tr>
238: <tr><td>3.1</td><td>3.2</td></tr>
239: </tbody>
240:</table>


IE: Não aconteceu nada
Firefox: Height funcionou, mas não exibiu o scroll
Opera: Não aconteceu nada

segunda-feira, 19 de novembro de 2007

Dicas Javascript

Hoje eu vou começar uma série onde eu vou postar dicas de Javascript que podem salvar em momentos de apuro.

1. Como converter um float para inteiro sem arredondamento.

É fácil. Bastar usar a notação:

1:var real = 1234.56;
2:var inteiro = real | 0;
3:alert(inteiro);
A saída será "1234". Se você usasse Math.round() a saída seria "1235".

2. Como gerar números aleatórios dentro de um intervalo.

O Javascript fornece a função Math.random() que gera números reais entre 0 e 1. Muitas vezes queremos números inteiros entre um intervalo. Eu criei a função random() a seguir para este fim:

 1:/**
2:* Gera números aleatórios inteiros entre um intervalo
3:* @author Daniel Castro Machado <daniel@cdt.unb.br>
4:* @param int valorIni Valor inicial.
5:* @param int valorFim Valor final.
6:* @return int Valor randômico
7:* @copyright
8:*/
9:function random(valorIni, valorFim) {
10: var numRandom;
11: do numRandom = Math.random(); while (numRandom == 1); // Evita gerar o número valorFim + 1
12: return (numRandom * (valorFim - valorIni + 1) + valorIni) | 0;
13:}

Comentários sobre a função:

  • O número gerado por Math.random() não pode ser 1 pois o resultado sairia do intervalo

  • Não usei Math.round() pois, neste caso, o primeiro e o último número teriam 50% menos chance de ocorrer.

  • O 1 que é somado garante que se busque no intervalo aberto.



3. Embaralhar um Array

Essa é uma função similar à função shuffle() do PHP. Ela embaralha o Array informado.

 1:/**
2:* Gera um Array embaralhado a partir de um Array passado por parâmetro.
3:* @author Daniel Castro Machado <daniel@cdt.unb.br>
4:* @param Array arrayOrigem
5:* @return Array
6:* @copyright
7:*/
8:function shuffle(arrayOrigem) {
9: var arrayDestino = new Array();
10: var indice;
11: while (arrayOrigem.length > 0) {
12: indice = random(0, arrayOrigem.length - 1);
13: arrayDestino[arrayDestino.length] = arrayOrigem[indice];
14: arrayOrigem.splice(indice, 1);
15: }
16: return arrayDestino;
17:}

Comentários sobre a função:

  • Ela usa a função random() que eu criei acima.

  • Até onde eu sei não tem como passar variáveis por referência em Javascript (se alguém souber como, me diga!). Então não dá pra usar como no PHP - shuffle(vetor), mas tem que se redefinir o vetor na mão: vetor = shuffle(vetor).

terça-feira, 6 de novembro de 2007

Validando Javascript no Ajax

No Tutorial Rápido de Ajax que eu escrevi eu comentei que os códigos Javascript não são validados ao serem escritos na página. Mas, é lógico, que sempre queremos validá-los. Então hoje eu vou apresentar uma solução para isso.

 1:/**
2:* Realiza uma requisição AJAX e processa a resposta.
3:* @param string URL URL do script que irá processar a requisição.
4:* @param string param Variáveis enviadas. Exemplo: "nome=joao&senha=123456".
5:* @param string IDResposta ID do elemento onde a resposta será escrita.
6:* @author Daniel Castro Machado <daniel@cdt.unb.br>
7:*/
8:function requisita(URL, param, IDResposta) {
9: requisicao.open("POST", URL, true);
10: requisicao.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
11: requisicao.send(param);
12: requisicao.onreadystatechange = function() {
13: var campoResposta = document.getElementById(IDResposta);
14: switch (requisicao.readyState) {
15: case 2:
16: campoResposta.innerHTML = 'Carregando, aguarde...';
17: break;
18: case 4:
19: if (requisicao.status == 200) {
20: campoResposta.innerHTML = requisicao.responseText;
21: var arScripts = campoResposta.getElementsByTagName("script");
22: var scriptTotal = document.createElement("script");
23: for (scriptParcial in arScripts) scriptTotal.text += scriptParcial.innerHTML;
24: document.body.appendChild(scriptTotal);
25: } else {
26: campoResposta.innerHTML = "Erro na resposta do servidor";
27: }
28: break;
29: }
30: }
31:}
A função requisita() pode ser um função genérica para tratamento de requisições Ajax. Ela exige como parâmetros a URL, as variáveis URL e o ID do elemento onde será escrita a resposta. Esta função faz o papel, por exemplo, do window.open() nas requisições tradicionais.

O que ela faz é:

  1. Envia a requisição.

  2. Ao receber uma resposta OK (status 200), escreve o código HTML em um área da página chamada areaResposta. Este código contém nenhum, um ou vários scripts (que infelizmente não são validados por padrão).

  3. Então recupera todos estes scripts através de DOM.

  4. Depois, para cada script desses, recupera seu conteúdo.

  5. Em um novo elemento de script é inserido estes conteúdos.

  6. Depois insere o script na página com appendChild().


Em outras palavras, para você usar o Ajax, basta instanciar o objeto XMLHttpRequest e usar a função requisita() para fazer as requisições. Nunca foi tão fácil usar Ajax. Nem mesmo é preciso entender de Ajax. Basta usar os códigos postados aqui e não será mais preciso se preocupar com os detalhes sujos de implementação.

P.S.: A solução alternativa seria usar eval() - como já foi dito no post anterior. Mas, neste caso, percebeu-se que as funções não foram validadas corretamente.

sábado, 27 de outubro de 2007

Tutorial rápido de Ajax

Ajax com PHP

Ajax é a sigla de Asynchronous JavaScript and XML.

O termo “assíncrono” – neste caso - significa que o usuário não precisa esperar que uma requisição seja processada para mandar outra(s).

Ajax não é uma linguagem de programação, mas uma técnica sugerida pelo Google em 2005.

Com Ajax é possível fazer requisições ao servidor sem submeter a página e assim criar sites parecidos com aplicações desktop (vide o Gmail, por exemplo) com melhor usabilidade e menor tráfego de dados.

A desvantagem é um pequeno aumento na complexidade da implementação e problemas com a inexistência de links para páginas criadas com essas requisições que impedem o usuário de ter uma referência a uma página específica (como fazer bookmark).

O Ajax é suportado pelos seguintes browsers: Internet Explorer 5.0+, Safari 1.2, Mozilla 1.0 / Firefox, Opera 8+ e Netscape 7.

O objeto XMLHttpRequest

É o ponto chave do negócio. Este objeto manipula as requisições e as respostas do Ajax.

A maioria dos fabricantes de browser implementa em Javascript uma classe nativa chamada XMLHttpRequest enquanto a Microsoft implementa uma classe ActiveXObject, mas ambos com interface semelhante.

Propriedades-chave:


  • readyState: integer – estado atual da requisição

  • responseText: string – a resposta do servidor

  • status: integer – status de resposta (exemplo: se for 200, a requisição está ok, se for 404, a página não foi encontrada)

Métodos-chave:


  • setRequestHeader() – define o cabeçalho da requisição.

  • onreadystatechange() – evento acionado quando há mudança no estado da requisição (atributo readyState)

  • open() – abre e configura uma conexão com o servidor

  • send() – envia a requisição


Passos para a criação de uma rotina em Ajax:

1.) Definir o elemento que enviará a requisição

Normalmente a requisição é feita através de algum evento de um input, por exemplo, ao clicar em um botão.

2.) Instanciar o objeto XMLHttpRequest em Javascript. Esse objeto irá manipular a requisição e a resposta.

A rotina de criação sempre será como segue:

 2:var requisicao;
3:
4:function criaObjetoAjax() {
5:
6: try { // Firefox, Opera 8.0+, Safari
7: requisicao = new XMLHttpRequest();
8: } catch (e) { // Internet Explorer
9: try {
10: requisicao = new ActiveXObject("Msxml2.XMLHTTP");
11: } catch (e) {
12: try {
13: requisicao = new ActiveXObject("Microsoft.XMLHTTP");
14: } catch (e) {
15: alert("Seu browser não suporta AJAX!");
16: return false;
17: }
18: }
19: }
20:}

3.) Enviar requisições

Primeiramente, definir – se for o caso - as variáveis URL.
Exemplo:

1:var param = 'nome=joao&senha=123456';

Definir o cabeçalho da requisição (o método POST não funcionará direito sem essas definições, pois os dados são enviados no cabeçalho)



1:requisicao.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2:requisicao.setRequestHeader('Content-length', param.length);
3:requisicao.setRequestHeader('Connection', 'close');


Evocar os seguintes métodos do XMLHttpRequest (que são primitivas de um serviço na camada de transporte. Para mais informações, estude arquiteturas de redes OSI ou TCP/IP)

  • open() - Abre a conexão

  • send() - Envia os dados

O método open recebe os argumentos:


  • Método de requisição (“GET” ou “POST”)

  • URL do script PHP no servidor

  • Se a conexão é assíncrona (true ou false)
Se o método for GET, os parâmetros devem ser enviados na URL. Se o método for POST, o método send() recebe os dados (que no caso é a variável param) para escrever no header da requisição.

4.) O script server-side

O script PHP no servidor recebe os dados nas variáveis $_GET ou $_POST respectivamente, é processado e gera uma resposta em formato de texto - que nada mais é do que o output do script.


5.) A propriedade readyState:


A propriedade readyState do objeto XMLHttpRequest armazena o estado atual da requisição. Seus valores possíveis são:


0: O request não está inicializado
1: O request foi configurado
2: O request foi enviado
3: O request está em processo
4: O request foi completo

6.) O evento onreadystatechange

O evento onreadystatechange do objeto XMLHttpRequest ocorre toda vez que a propriedade readyState muda. Ouvindo este evento vamos processar a resposta vinda do servidor quando seu estado for 4 (concluída). A resposta é guardada no atributo responseText do objeto XMLHttpRequest.


1:requisicao.onreadystatechange = function() {
2: if (requisicao.readyState == 4) {
3: document.getElmentById('resposta').innerHTML = requisicao.responseText;
4: }
5:}

Considerações:


  1. Nem sempre uma requisição é acionada por uma ação do usuário. Um auto reload na página também pode requerer dados. Um exemplo disso é um sistema de chat que precisa fazer requisições periódicas para saber se houve novas mensagens.

  2. Para exibir uma mensagem do tipo “Carregando...”, deve-se tratar a propriedade readyState quando seu valor for 2 ou 3.

  3. Se a resposta enviar um javascript, este não será validado automaticamente. Para saber como validar os scripts enviados, leia o tutorial http://oreidophp.blogspot.com/2007/11/validando-javascript-no-ajax.html.

  4. Também é possível enviar como resposta um XML contendo dados para serem tratados via Javascript.

Exemplo

Vamos colocar o que foi dito em prática. O exemplo a seguir é composto de dois arquivos na raiz da aplicação. É enviado o nome do usuário e recebido nome do servidor de aplicação.

Tela:



Tela do exemplo


index.html
   1:<html>
2: <body>
3: <h1>Teste de Ajax</h1>
4: Seu nome: <input type='text' name='nome' id='nome' />
5: <input type='button' value='Requisitar' onclick='requisita()' />
6: <div id='resposta'></div>
7: </body>
8:</html>
9:
10:<script type='text/javascript'>
11: var requisicao;
12: try { // Firefox, Opera 8.0+, Safari
13: requisicao = new XMLHttpRequest();
14: } catch (e) { // Internet Explorer
15: try {
16: requisicao = new ActiveXObject("Msxml2.XMLHTTP");
17: } catch (e) {
18: try {
19: requisicao = new ActiveXObject("Microsoft.XMLHTTP");
20: } catch (e) {
21: requisicao = false;
22: }
23: }
24: }
25:
26: function requisita() {
27: if (!requisicao) {
28: alert('Seu browser não suporta Ajax');
29: return false;
30: }
31:
32: requisicao.onreadystatechange = function() {
33: var resposta = document.getElementById('resposta');
34: switch (requisicao.readyState) {
35: case 2:
36: resposta.innerHTML = "Carregando...<br/>";
37: break;
38: case 4:
39: if (requisicao.status == '200') {
40: resposta.innerHTML = requisicao.responseText;
41: } else {
42: resposta.innerHTML = "<p><b>Erro no servidor</b></p>";
43: }
44: }
45: }
46: var param = "nome=" + document.getElementById('nome').value;
47: requisicao.open("POST", "processaRequisicao.php", true);
48: requisicao.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
49: requisicao.setRequestHeader('Content-length',param.length);
50: requisicao.setRequestHeader('Connection','close');
51: requisicao.send(param);
52: }
53:</script>

processaRequisicao.php

   1:<hr/>
2:Ola <?= $_POST['nome'] ?>
3:<br/>
4:O software do servidor de aplicacao &eacute; <?= $_SERVER["SERVER_SOFTWARE"] ?>
5:<hr/>

Wellcome Você!

Oi!
Meu nome é Daniel Castro Machado.
Sou desenvolvedor WEB e utilizo a linguagem PHP 5.0.

A idéia desse blog é a seguinte: eu deparo com diversas situações de aprendizado no dia-a-dia do meu trabalho e então, a partir de hoje, eu vou condensar esse aprendizado no blog.

Vai me servir como fixação das idéias e também pode ser útil para outros incautos programadores.

Então, mãos à obra!