Pesquisei e quebrei a cabeça para achar essa solução… tanto que questionei entre dar apenas o ‘mapa’ ou o script pronto. Mas sou um cara open-source por natureza, por isso vou fazer as duas coisas.
Bem, todos já sabemos que comandos em javascript não ativam os botões de histórico do navegador, mesmo que mudem 100% do conteúdo exibido. Isso não é legal, pois sabemos que o usuário busca usar os recursos que conhece e o botão ‘Voltar’ é uma instituição, existe desde que o mundo é mundo. Eu me sentia meio que ‘na obrigação’ de possibilitar isso ao usuário.
Pensei então, há alguns meses em uma solução - que me serviu no momento, mas que não ativava os botões, apenas criava um ‘histórico de comandos’ num array, com funções para adicionar, exibir e testar itens do histórico. Com isso eu fazia os meus próprios botões de histórico. Achei que fosse suficiente, mas hoje vejo que não, pois na maior parte dos casos o usuário nem entende que há um histórico ‘paralelo’ e que ele precisa clicar em outros botões para navegar…
Veja o script original:
// histórico de comandos - 2006-06-07
_ajax.history = {
‘items’: [],
‘currentIndex’: 0,
‘go’: function(ref) {
if(_ajax.history.items[_ajax.history.currentIndex + ref] false)
_ajax.history.currentIndex += ref;
else return;
new Function(_ajax.history.items[_ajax.history.currentIndex])();
},
‘add’: function (str) {
if(str == _ajax.history.items[_ajax.history.currentIndex]) return;
_ajax.history.currentIndex = _ajax.history.items.length;
_ajax.history.items.push(str);
},
‘hasBack’: function() {
return (_ajax.history.items[_ajax.history.currentIndex - 1] || false) ? true : false;
},
‘hasForward’: function() {
return (_ajax.history.items[_ajax.history.currentIndex + 1] || false) ? true : false;
}
};
Caí de cabeça atrás da solução, que eu já sabia, tinha algo a ver com a propriedade hash do objeto location. Descobri algumas possibilidades, a começar pelos famosos frameworks (que eu abomino…), algumas funções interessantes que só funcionavam em Mozilla, outras gigantescas demais para o meu gosto. Tentei então entender como as coisas eram feitas e fazer eu mesmo. Este é sempre o método mais enriquecedor (mas nem sempre é o mais eficiente… é bom lembrar -rsrsrs).
Entendendo
O objeto window.location tem uma propriedade chamada ‘hash’, que mostra ou define aquela parte da URL que vem no final, depois do caracter ‘#’ - que usamos para navegar para diferentes pontos na mesma página, com, por ex.:
<a name="meu_hash"></a> e chamamos com: <a href="#meu_hash">meu_hash</a>Pois é, ele é a chave para o histórico do navegador, pois ao mudar o hash, mudamos a URL. Então se ao executar um comando, eu mudar o hash o navegador armazena como uma nova página? A resposta é não. Se não há um clique explícito do usuário em um link como o descrito acima (com um A NAME="…"), ao clicar no botão Voltar, nada acontece! O IE nem habilita o botão!!! Bem, mas a URL está diferente e é isso que vamos usar. Usaremos uma variável para armazenar o hash e um setInterval para testá-lo a intervalos regulares. Dê uma olhada nesse link: http://juliogreff.wordpress.com/2006/10/20/ativando-o-botao-voltar/.
Com o script que o Júlio mostra, resolve-se a questão. Mas resta um problema: o IE não habilitou o botão voltar apenas com a mudança do hash… Mais pesquisas e mais pesquisas para achar a solução, que quando foi encontrada me pareceu tão óbvia que não sei por que não pensei nisso antes (sempre pensamos isso, né?). Quando carregamos um frame ou iframe o IE cria um novo item no histórico! Veja a página de onde tirei a idéia: http://www.contentwithstyle.co.uk/Articles/38/fixing-the-back-button-and-enabling-bookmarking-for-ajax-apps.
Esse exemplo é crossbrowser, mas muito complicado. Serviu para esclarecer, mas não tive vontade de usá-lo.
Bem, baseado nesses scripts resolvi criar um terceiro, fundindo com o que já tinha pronto (mostrado acima) criei o objeto ajaxHistory. Vou falar sobre a lógica que usei antes de mostrar o script. Basicamente preservei os métodos e propiedades do antigo objeto e acrescentei novos métodos para permitir o uso do objeto history do navegador.
Em nosso objeto haverá um array para armazenar os comandos (como strings) chamado ajaxHistory.items e um inteiro que indica o índice do item exibido no momento, ajaxHistory.currentIndex. O sistema original funciona da forma mais simples possível. A cada comando que modifique o conteúdo da página, executamos ajaxHistory.add enviando uma string que se executada como comando reproduz a operação que modificou a página. Depois podemos usar os métodos ajaxHistory.go ou ajaxHistory.goTo para navegar pelos itens do nosso ‘histórico de comandos’. Além do método goTo, o array ajaxHistory.captions foi adicionado, possibilitando ajustar o título da página de acordo com o item exibido. Aí podemos usar ajaxHistory.hasBack e ajaxHistory.hasForward para testar se há itens atrás ou adiante do atual e assim habilitar ou desabilitar nossos botões personalizados de histórico.
Ok, mas e para usar os benditos botões de histórico do browser? Para isso vários métodos foram criados, mas para executar, basta chamar o método ajaxHistory.activateBrowserHistory no onload da página, uma única vez. Isso dispara uma série de eventos que em conjunto habilitam o histórico do navegador. Vamos a eles.
A lógica e a execução da coisa são diferentes para Mozilla e IE (novidade…).
Em ambos os casos o hash é modificado ao criar um novo item ou ao carregar um item do histórico (ajaxHistory.setHash).
No Mozilla criamos um setInterval chamando o método ajaxHistory.checkHash a cada 1/10 de seg. testando se o hash é igual a ajaxHistory.currentIndex, se for diferente, o usuário clicou no botão voltar (ou avançar). O hash é setado com o valor do índice do item no array ajaxHistory.items, então ajaxHistory.goTo é chamado com o hash como parâmetro.
No IE um iframe é inserido na página, com display:none. Este iframe carrega o arquivo ‘historyframe.html’ que deve ser criado como descrito abaixo:
function checkHistory() {
var pi = parent.location.hash.replace(/#/,'’), si = location.href.replace(/^.+\?/,'’);
if(si && pi && (parent.ajaxHistory || false))
if(pi != si) parent.ajaxHistory.goTo(si);
}
</script></head><body onLoad="checkHistory();"></body></html>
No caso do IE, ajaxHistory.setHash recarrega o iframe enviando na query string o valor do índice, assim: ‘historyframe.html?2′, por exemplo. O arquivo ‘historyframe.html’ ao ser carregado testa o índice enviado na URL com o hash na URL da janela principal, se forem diferentes, ajaxHistory.goTo é chamado com o índice enviado na URL como parâmetro.
O Mozilla, ao contrário do IE, habilita os botões mas não há ação mesmo quando o iframe é recarregado, portando os dois métodos foram necessários. Bem, lá vai o script:
* ajaxHistory - histórico de comandos para navegação por Ajax
* ———————————————–
* autor: Cau Guanabara
* data: 2006-06-07 :: 2006-11-07
* ———————————————–
*/
var ajaxHistory = {
‘items’: [],
‘captions’: [],
‘currentIndex’: 0,
‘go’: function(ref) {
if(this.items[this.currentIndex + ref] || false) this.currentIndex += ref;
else return;
if(this.activeHistory) this.setHash();
if(this.captions[this.currentIndex]) document.title = this.captions[this.currentIndex];
new Function(this.items[this.currentIndex])();
},
‘goTo’: function(ind) {
if(this.items[ind] || false) this.currentIndex = ind;
else return;
if(this.activeHistory) this.setHash();
if(this.captions[this.currentIndex]) document.title = this.captions[this.currentIndex];
new Function(this.items[this.currentIndex])();
},
‘add’: function(str, cap) {
if(str == this.items[this.currentIndex]) return false;
this.currentIndex = this.items.length;
this.items.push(str);
this.captions.push(cap || false);
if(this.activeHistory) this.setHash();
return true;
},
‘hasBack’: function() { return (this.items[this.currentIndex - 1] || false) ? true : false; },
‘hasForward’: function() { return (this.items[this.currentIndex + 1] || false) ? true : false; },
‘activeHistory’: false,
‘activateBrowserHistory’: function() {
if(document.all) this.makeIframe();
else setInterval("ajaxHistory.checkHash()", 100);
this.activeHistory = true;
},
‘makeIframe’: function() {
this.iframe = document.createElement(’iframe’);
this.iframe.style.display = ‘none’;
this.iframe.src = ‘historyframe.html’;
document.getElementsByTagName(’body’)[0].appendChild(this.iframe);
},
‘checkHash’: function() {
var curHash = location.hash.replace(/#/,'’);
if(this.currentIndex != curHash) this.goTo(curHash);
},
’setHash’: function() {
top.location.hash = this.currentIndex;
if(document.all)
this.iframe.contentWindow.location.href = ‘historyframe.html?’+this.currentIndex;
}
};
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" language="javascript" src="ajax_history.js"></script>
<script type="text/javascript" language="javascript">
function request(command, caption) {
ajaxHistory.add(command, caption);
document.title = caption;
new Function(command)();
}
</script>
</head>
<body onload="ajaxHistory.activateBrowserHistory();">
Clique nos links e depois navegue pelo histórico<br /><br />
<p><a href="javascript://" onclick="request(’alert(\’link 1\’);’,'link 1′)">link 1</a><br />
<a href="javascript://" onclick="request(’alert(\’link 2\’);’,'link 2′)">link 2</a><br />
<a href="javascript://" onclick="request(’alert(\’link 3\’);’,'link 3′)">link 3</a> </p>
</body>
</html>










não consegui fazer rodar o código… diz que ajaxHistory não esta definido. Pode me ajudar?
Por Cadu em 2006-11-15 09:48:18, quarta
O sistema do worpress modifica as aspas por acentos ou sei lá o que… será preciso substituir as aspas. Deve ser isso
Por Cau Guanabara em 2006-11-15 09:48:18, quarta
Não consegui, já fiz a troca e testei… nada!
Devo estar me confundindo na hora de aspas duplas e simples…
Tem como colocar pra download ou mandar por email?
Obrigado!
Por Cadu em 2006-11-15 09:48:18, quarta
Coloquei para download aqui:
http://cauguanabara.jsbrasil.com/scripts/ajax_history.js
Por Cau Guanabara em 2006-11-15 09:48:18, quarta
agora funcionou redondo! Valeu pela ajuda, obrigado!
Abraços!
Por Cadu em 2006-11-15 09:48:18, quarta
Olá…
Estou precisando bastante de uma solção para para esse problema.
Baixei o código da sua solução e coloquei seguinte trexo:
… onclick=”request(’document.getElementById(’teste’).innerHTML = ‘xxxxxx’;',’teste’);” …
ele altera a url ai eu avanço de página quando volto a url lá é a mesma mais não aparece o conteudo.
o que aconteçe ???
Obrigado.
Por Marcelo em 2006-11-15 09:48:18, quarta
No Firefox esta funcionando no IE não.
Alguma dica ?
Obrigado.
Por Marcelo em 2006-11-15 09:48:18, quarta
Comigo só funcionou no FF… se alguem souber pq me ajudem por favor…
Por Fernando em 2006-11-15 09:48:18, quarta
Coloquei um exemplo de funcionamento no ar:
http://cauguanabara.jsbrasil.com/scripts/historybuttons/
Testado em IE7 e FF2
Por Cau Guanabara em 2006-11-15 09:48:18, quarta
Parabéns pelo dica!
Realmente sensacional!
O único probleminha é que no IE o script não carrega as imagens da div… no FF funciona perfeitamente.
Como eu poderia fazer pra arrumar esse bug no código?
Brigadão!
Por Simone em 2006-11-15 09:48:18, quarta