Back Button Improved!

Depois de alguns aprimoramentos, essa técnica se tornou muito melhor. Como esse post está desatualizado, considere ler sua continuação: Histórico para Navegação via JavaScript.

Desde minha última postagem, muita coisa aconteceu… O portal Ajax Online foi hackeado (juro que não fui eu) e está fora do ar, tive a oportunidade de conhecer o IE7 (realmente estou atrasado nesse ponto), fui convidado para ser colunista do yourDevelop, e mais outras coisinhas.

Como prometi, estou postando a versão cross-browser e acessível do meu script que faz o botão voltar funcionar. Na verdade, esse script é mais uma cópia do Mike Stenhouse, mas simplifiquei muita coisa, e melhorei um pouco no que foi possível. Alguns problemas ainda persistem no IE, mas são um tanto incomuns. Não vou explicar o código, só a parte lógica, pois os códigos já foram explicados anteriormente.

Diferente do Cau Guanabara, resolvi os problemas de refresh, bookmark e histórico (voltar e avançar) em um único script, funcionando em Firefox e IE. Tive a paciência de ler todo o script do Mike Stenhouse e entender todo ele, e criar um novo, simplificando alguns aspectos.

A lógica do Voltar-Avançar continua sempre a mesma. Manipulamos o botão através dos hashes (e iframes também, no caso do IE), que ativam o botão voltar. Neste caso, comparamos o hash da página com o local que está carregado dentro da página. Por exemplo: na barra de endereços, temos “http://localhost/index.htm#page1″, mas na página está carregado o conteúdo pertencente ao hash “page2″. Assim, quando a função “checkChanges” for executada novamente, ela vai sincronizar o hash com o conteúdo.

A parte do refresh e bookmarking é extremamente fácil. Quando a página é carregada, a função “checkChanges” (ou “checkBookmark”, no IE) é chamada, e apenas sincroniza o conteúdo com o hash inicial, sem mais enrolações.

Modificações

Em relação ao script original, modifiquei umas coisinhas. Uma delas foi a maneira como o iframe é criado. Em vez de “document.write”, usei DOM. Simples, qualquer um fazia.

As outras modificações, um pouco mais complicadas, se referem todas aos objetos urlFix e iFrameFix. Usei JSON em vez dos objetos como funções. Isso evita aquele “new”. Ahh! Também não usei o PageLocator.makeNewLocation. Usei window.location.hash, que faz a mesma coisa e ocupa menos código.

Usando no seu site

Em um comentário, perguntaram-me como proceder para utilizar o script em uma página. Acabei não explicando na hora porque ficaria muito difícil. Agora ficou fácil (nunca leram isso no Banco Postal???). Vamos lá, então.

Insira tudo que estiver entre as tags no seu site, sem exceções. E insira os links normalmente também, apontando para a página que deveria ser carregada sem o uso de Ajax. Lembre-se da query string “hash=”. Dentro daquilo deve estar todas as query strings que sejam necessárias (eu sei, é difícil usar mais que uma).

O script fará quase tudo sozinho, você só precisará da função doGetPage. Ela será a responsável pelas requisições Ajax. Faça como uma função qualquer, passando o atributo hash como query string.

E o código???

Pensou que eu ia esquecer? Não sou tão mal assim. O código está disponível para download, zipado, aqui O código acabou se perdendo no tempo e no espaço. Leia a atualização do post para algo ainda melhor! Ele tem tinha:

  • A página principal index.html
  • A página mock-page.php

Tudo funciona direitinho, menos doGetPage. Usei apenas para simular… Apesar de dever ser incluída, não coloquei content.php também. Por quê? Porque não faremos nada em Ajax aqui! Apenas simulando…

[update]Dica do Dekassegui, pra retirar o bloco de script suplementar lá embaixo: Subversão Parcial[/update]

Depois de alguns aprimoramentos, essa técnica se tornou muito melhor. Como esse post está desatualizado, considere ler sua continuação: Histórico para Navegação via JavaScript.

18 de novembro, 2006

Botão Voltar para IE

Depois de alguns aprimoramentos, essa técnica se tornou muito melhor. Como esse post está desatualizado, considere ler sua continuação: Histórico para Navegação via JavaScript.

Como todos já devem saber, meu código para simular o botão voltar não funciona no IE. Mas, inspirado na idéia de Mike Stenhouse, apresentada a mim pelo Cau Guanabara, criei um código que funciona no IE.

Bem, inicialmente meu código tem 2 probleminhas, facilmente resolvidos:

  • Ele não funciona no Firefox. Mas basta integrar minhas duas funções e tudo se resolve.
  • Ele é completamente “inacessível”. A acessibilidade foi por água abaixo. Mas existem técnicas para desfazer isso. Não coloquei aqui, pois meu objetivo é ensinar o botão voltar.

Ambos problemas podem ser resolvidos. E não é difícil. Para resolve-los, pretendo escrever mais um código. Vou avisando que vai ser grande, mas melhor que os dois que já criei. Se você aceita as condições supra citadas, proponho: continuemos…

O conceito utilizado é simplesmente o mesmo: comparar o hash com o local da página, que estará em uma variável, que será definida através de uma função. A técnica que é um pouco diferente: em vez de apenas hashes, utilizaremos iframes, que ativam o botão voltar no IE.

Passos Básicos

Para utilizarmos essa técnica, estou usando um XHTML normal. Por razões de acessibilidade (um pouco, né), estou usando também a função “addEvent()”, para manipular o evento “window.onload”. Vamos lá:

<html>
<head>
<title>Botão Voltar no IE</title>
<script>
function addEvent(obj, evType, fn){
	 if (obj.addEventListener){
		 obj.addEventListener(evType, fn, true);
		 return true;
	 } else if (obj.attachEvent){
		 var r = obj.attachEvent("on"+evType, fn);
		return r;
	 } else {
		return false;
	 }
}
</script>
</head>
<body>
<div id="container"> </div>
<ul>
<li><a href="javascript:document.getElementById('ajaxnav').setAttribute('src', 'mock-page.php?hash=1');">Page 1</a></li>
<li><a href="javascript:document.getElementById('ajaxnav').setAttribute('src', 'mock-page.php?hash=2');">Page 2</a></li>
<li><a href="javascript:document.getElementById('ajaxnav').setAttribute('src', 'mock-page.php?hash=3');">Page 3</a></li>
</ul>
</body>
</html>

Observe o motivo da inacessibilidade: os links. Por que eles apontam para um objeto? Calma… Esse objeto, por dedução, é um iframe. Mas onde ele está? Temos que criar ele via JavaScript (não tentei criar direto, acho que é assim pra “enganar” o validador). Antes do fechamento do corpo da página, insira:

<script>
var windowlocator = window.location.hash.split("#")[1] || "1";
document.write("<iframe id='ajaxnav' name='ajaxnav' src='mock-page.php?hash="+windowlocator+"' style='display: none;'></iframe>");
</script>

E aí está. Aliás, não está, ele é invisível(sério???)! E ele aponta para uma página “mock-page.php”. Essa foi pura e simplesmente copiada do Mike. Mais tarde veremos ela.

O Script

Agora sim, o temido script.

var locator;		// Variável c/ local da pagina
function iFrameFix() {
	locator = document.frames['ajaxnav'].getLocation().split("?hash=")[1] || "1"; // A mesma variavel
	// Note que ela tem um valor "1" caso nada seja definido
	setTimeout("checkBookmark()",100);	// Função para checar Bookmark ou Refresh
}

Sinceramente, não sei porque um timeout ali em cima. Aqui funcionou direitinho sem ele.

Observe com atenção, caro aprendiz: tem uma função getLocation ali. Ela pegará o hash da página “mock-page.php”. Curioso? Dentro de uma página comum, temos um script:

	<script type="text/javascript">
function getLocation() {
	return '<?php print "http://" . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] . "?" . $_SERVER['QUERY_STRING'] ?>';
}
</script>

Aquela função retorna um valor passado pelo PHP. Não convém ficar explicando PHP agora, até porque eu não sou muito bom nisso. Agora vamos a mais uma função:

function checkBookmark() {
	window.location.hash = locator || "1";	// Local do Hash
	checkWhetherChanged(0);		// Checar mudanças
}
function checkWhetherChanged(location) {
	var locator = document.frames['ajaxnav'].getLocation().split("?hash=")[1] || "1";	// De novo, para não ter problemas
	if(locator != location) {	// Se página != hash...
		doGetPage(locator);		// Requisição Ajax
		window.location.hash = locator;	// E mudamos o hash da página
	}
	setTimeout("checkWhetherChanged(" + locator + ")", 200);	// Pequeno intervalo de tempo, e repetimos tudo, infinitamente
}

Acho que o código é familiar. O importante é saber fazer a requisição Ajax. Não vou explicar ela aqui, você vai ter que sofrer e cria-la sozinho. Para isso, faça uma query string ” “valor=” + locator”, algo assim.

Tá legal, tá tudo definido bonitinho, mas e quando começa tudo? Quando a página carregar, e temos que definir isso também.

addEvent(window, "load", iFrameFix);

Bem, acho que acabou… Como o pessoal disse que eu confundi muito no outro artigo, vou explicar o “fluxo do script”.

[página carregada] Executamos "iFrameFix()";
[iFrameFix()] Definimos "locator" como sendo o hash do iframe;
			  Executamos "checkBookmark()";
[checkBookmark()] Definimos o hash da página como sendo igual a "locator" ou "1";
                  Executamos "checkWhetherChanged(0)", com parâmetro 0;
[checkWhetherChanged()] Pegamos "locator" de novo (para que sejam verificadas as modificações);
						Se "locator" for diferente de "location", fazemos uma requisição Ajax;
						E definimos "window.location" com um hash "locator";
						A cada 200 milissegundos, executamos essa função de novo;

E em breve estarei colocando aqui o código completo, unindo as duas soluções, e de forma mais “acessível” também.

Depois de alguns aprimoramentos, essa técnica se tornou muito melhor. Como esse post está desatualizado, considere ler sua continuação: Histórico para Navegação via JavaScript.

15 de novembro, 2006

Ficando Bem-Informado

Como sempre diz meu pai, a base para qualquer profissão hoje em dia é a Informação. Estar informado, estar atualizado. Isso é indispensável. Difícil às vezes, mas indispensável.

Se você quer chegar primeiro, sempre esteja informado com tudo que acontece. Tudinho mesmo. Como? Vou dar as dicas aqui!

Use e Abuse dos Feeds

Se você entrar em um site, e se interessar pelo conteúdo, assine o feed. Sem nem pensar. Eles são dem nem pensar. Eles são de graça, não ocupam muito tempo para verificar alguma coisa nova e, algumas vezes, te poupam de visitar um site (Disponibilize seus feeds completos). Já vi gente com mais de 700 feeds assinados. Estou beirando os 50 ainda (estou tentanto, tá!).

A quantidade de feeds ajuda, mas não é essencial. Essencial é o conteúdo de boa qualidade que se pode (e deve) encontrar neles. Sejam esses textos técnicos (como o meu blog) ou de temas variados (como a vida do vizinho do lado, ou como o Contraditorium, com temas dos mais variados). Não tem nenhum feed assinado? Nem sabe o que é isso? Comece pelo Bloglines, comecei por ele e não consegui me adequar a nenhum outro, mesmo que uns digam que está “ultrapassado”. Hoje uso o Google Reader.

Esteja aberto a nosvas idéias

Não visite sempre os mesmos sites. Não fique naquelas “panelinhas”. Sempre que aparecer um link, abra-o, dê uma chance e você vai ver que poderá receber desse site muito mais do que esperava.

Hoje em dia, com a explosão dos blogs (já é de um tempinho atrás), eles se tornaram uma das melhores maneiras para ficar bem informado. Leia quantos puder, quanto mais, melhor. Visitar fóruns de vez em quando ajuda bastante também.

Tenha um blog

“Tenha um blog”? É isso mesmo. Com um blog você se sente na “obrigação” de passar alguma coisa para seus leitores, mesmo que seja em um intervalo de tempo grande, dependendo de sua disponibilidade. Dessa maneira, a obrigação de ficar bem informado é maior. Criei o meu blog sem muito entusiasmo no começo, mas agora não fico mais sem ele. Além disso, um blog estimula sua criatividade, sua leitura e escrita (nem sempre), e é uma boa distração também.

Mas se você não tem tempo para escrever um blog, converse com pessoas que tenham os mesmos interesses que você (essa parte não é bem comigo, meus amigos são todos uns desinteressados por qualquer coisa). Você sempre transmitirá e receberá alguma coisa que será muito útil.

Leia, leia, leia…

Tá certo que ler um livro não é um dos passatempos preferidos dos brasileiros, mas torne um hábito. Um bom livro, um jornal, uma revista, até gibi serve. A informação muitas vezes pode estar implícita nesses lugares.

Mas e a Internet? Bem, essa é uma parte complicada. A Internet é uma ótima fonte de informações e leitura, mas é muito mal usada em geral. Com tudo o que você deve ter para visitar na Internet, às vezes fica difícil ler um texto inteiro com atenção. Então faça como eu: como não acesso Internet de casa, gravo todos os posts, artigos e textos que encontro no meu pen drive, e leio tudo em casa. Sem pressa nenhuma, até duas vezes quando o texto é interessante. Faça o teste: esqueça que você tem Internet e pare para ler aquele texto gigantesco.

Saia por aí!

Err… Essa parte não é bem sobre ficar informado, mas ajuda bastante. Não fique trancado no quarto o dia inteiro no computador, ou em cima dos livros. Saia, faça amigos, arranje uma namorada, jogue um futebolzinho de vez em quando, etc. Você ficará louco se fizer tudo o que eu disse aqui se não seguir essa última dica. Eu mesmo já beirei a “loucura” nesse sentido, de sonhar com tags (sério!!!).

Então fico por aqui, até a próxima!

12 de novembro, 2006

Utilizando o Método POST em Ajax

Como você já devia saber, o método GET só suporta o envio de 255 caracteres por vez. Com Ajax, isso costuma ser o suficiente, mas nem sempre. Em editores de texto, postagens em geral, cadastros, senhas (não é pelo tamanho, é que os dados não aparecem na URL)… Isso é conseguido por um método HTTP chamado “POST”. Possivelmente você já deve tê-lo usado, mas em Ajax…

Sim, é perfeitamente possível. Vamos lá então. Se você já tentou, provavelmente chegou perto de conseguir, algo como:

var xmlhttp = setXmlHttp(); // Função Personalizada
xmlhttp.open("POST", "http://localhost/post.php", true);
xmlhttp.send("seus_dados=via_post");

Essa é a base, mas não obteremos sucesso. Tudo o que fizemos, 100% mesmo, está correto. O problema é que falta mais alguma coisa. A primeira delas: o tipo de dados, não pode ser text/html ou text/xml, o padrão. O certo é o tipo de dados apropriado para envio de formulários: “application/x-www-form-urlencoded”. Vamos lá:

var xmlhttp = setXmlHttp(); // Função Personalizada
xmlhttp.open("POST", "http://localhost/post.php", true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");	// Setando Content-type
xmlhttp.send("seus_dados=via_post");

Tudo certo, irá funcionar. Pelo que sei, o método POST aceita uma quantidade enorme de dados, enorme mesmo. Tudo o que você tentar enviar passará. Não sei exatamente o quanto. Mas, por padrão, o tamanho máximo permitido é 4096, para evitar erros. Isso faz com que seus dados cheguem truncados as vezes. Setamos então um novo header: “Content-length”.

var xmlhttp = setXmlHttp(); // Função Personalizada
xmlhttp.open("POST", "http://localhost/post.php", true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");	// Setando Content-type
xmlhttp.setRequestHeader("Content-length", dados_a_enviar.length); // Comprimento do conteúdo=comprimento dos dados a enviar
xmlhttp.send(dados_a_enviar);

E agora sim estamos com tudo pronto para funcionar! Não falta mais nada.

É, na verdade falta apenas uma coisinha: como enviar os dados? Como você já viu, enviamos os dados através de xmlhttp.send(). Mas como? Lembra-se das famosas query strings? Da mesma maneira, mas sem o & inicial.

Recebendo os Dados

Além de enviar os dados, também devemos recebê-los corretamente. Ensinarei usando o PHP, mas poderia ser usada qualquer outra linguagem server-side.

Na verdade, para recebermos os dados, usamos o $_POST['variavel']. Nada mais simples. Mas há um probleminha: “A AÇÃO DO AJAX É FANTÁSTICA” chegaria truncada, mais ou menos assim: “AÇÃO DO AJAX É FANTÁSTICA”. Você saberia dizer por quê?

Por padrão, os dados são enviados, recebidos, manipulados e outras ações desconhecidas de minha pessoa no formato UTF-8. Por causa dos acentos, a língua portuguesa chegaria totalmente truncada, como mostrei acima. Solução: transformar para ISO-8859-1. Como?

<?php
header("Content-type: text/html; charset=iso-8859-1");	// Header
$var = utf8_decode($_POST['var']);	//Transformando caracteres
?>

Também poderíamos adicionar mais opções, como retirar tags e barras… Não vem ao caso.

Como muito bem sugerido pelo Mateus Pádua, podemos decodificar todo o $_POST de uma vez só, utilizando o mapeamento de array:

$_POST = array_map(utf8_decode, $_POST);

Outro porém: alguns bancos de dados preferem o UTF-8 para trabalhar. Nesse caso, precisamos guardar os dados nesse formato. Poooooortanto, precisamos fazer o inverso: transformar de ISO-8859-1 para UTF-8. Isso se faz através da função PHP utf8_encode(data).

Espero que tenha servido bem aos seus propósitos. Qualquer dúvida, comentem!

11 de novembro, 2006

Feeds Parciais para Móveis

Quando aderi a campanha dos feeds completos, do Rafael Arcanjo, pensei em contentar gregos e troianos com os feeds completos. Mas acabou de entrar no meu Bloglines um post de Aldemir Silva, Feeds Parciais para Dispositivos Portáteis. A “campanha” não é dele, mas fiquei sabendo pelo blog. Em resumo, a “campanha” fala sobre “analisar o outro lado da moeda”, ou seja, disponibilizar feeds resumidos para dispositivos móveis. Por quê? Leia aqui, “O outro lado da campanha dos feeds completos”. Realmente, existem vantagens e desvantagens.

A solução? Disponibilizar dois feeds: um resumido, um completo. Infelizmente, se depender do WordPress, vou ficar fora dessa. Estou dando uma olhada no FeedBurner agora, pra ver se a situação se resolve. Se alguém tiver uma idéia, me passe. Já está funcionando o feed parcial também: JulioGreff Parcial.

Na minha opinião, é bem legal essas idéias que surgem. E até concordo com a Bia. Visitei meu blog ontem pelo celular. Levou um tempinho pra carregar, mas estava lá. Meio desconfigurado, mas gostei. E espero que mais gente experimente os dispositivos móveis (eu só pude experimentar mesmo, não tenho dinheiro suficiente para grande tráfego de dados mesmo).

Enfim, está dada a largada para mais uma corrida de acessibilidade! E lá vou eu ver o que posso fazer…

10 de novembro, 2006