quinta-feira, 13 de março de 2008

Escapando textos em funções de javascript executadas em links

Para determinar a execução de uma função javascript no clique de um link temos duas possibilidades. Ou utilizamos o próprio atributo href da tag a com o protocolo javascript: ou adicionamos o atributo onclick fazendo a chamada à função.

Contudo o comportamento de ambos não é totalmente igual. Principalmente quando chamamos funções que passam como argumento algum texto escapado com a função escape. Normalmente usa-se esse escape para evitar error de javascript devido ao uso de aspas simples e duplas nos textos.

Veja abaixo dois exemplos de cógigo com o erro por não usar escape. O primeiro com aspas simples, que faz com que o javascript ache que o texto terminou antes do que deveria e o segundo com aspas duplas fazendo o navegador acreditar que o atributo terminou:
var textoComAspaSimples = "Quero um copo d'água";
var s = '<a href="javascript:alert(\'' + textoComAspaSimples+ '\')">Clique aqui</a>';
document.writeln(s);

var textoComAspaDupla = 'Você está com "sede"?';
var s = '<a href="javascript:void(0)" onclick="alert(\'' + textoComAspaDupla+ '\')">Clique aqui</a>';
document.writeln(s);
Para evitar esses erros uma boa idéia é utilizar a função escape. No entanto isso não funciona direito por href. Neste atributo o navegador interpreta o código escapado causando o mesmo erro. Isso pode ser observado no exemplo a seguir, no primeiro link gerado o erro acontece, no segundo não:
var textoComAspaSimples = "Quero um copo d'água";
var s = '<a href="javascript:alert(\'' + escape(textoComAspaSimples) + '\')">Clique aqui href</a><br/>';
s += '<a href="javascript:void(0)" onclick="alert(\'' + escape(textoComAspaSimples) + '\')">Clique aqui onclick</a>';
document.writeln(s);
O problema é que com essa solução a função que recebe este parâmetro precisa executar uma transformação reversa utilizando a função unescape. Caso contrário veremos algo parecido com o que o segundo link do exemplo acima mostra: Quero%20um%20copo%20d%27%C3%A1gua.

Implementando a transformação reversa na função que recebe teríamos algo como o mostrado abaixo. Uma nova função que recebe o parâmetro escapado e o transforma para utilizá-lo:
function escapedAlert(s) {
alert( unescape(s) );
}
var textoTodoErrado = "Sentes \"sede\"?\nQuero um copo d'água";
var s = '<a href="javascript:void(0)" onclick="escapedAlert(\'' + escape(textoTodoErrado) + '\')">Clique aqui onclick</a>';
document.writeln(s);
Mas isso ainda não é o ideal pois continuaríamos sem poder utilizar a função dentro do atributo href, e além disso precisaríamos sempre preparar as funções para receber parâmetros escapados. Uma outra alternativa é criar nossa própria função de escape. Como é mostrado no exemplo abaixo:
function escapeForLink(s) {
if(s) {
var r = s.split("\n").join("\\n");
r = r.split("\r").join("\\r");
r = r.split("'").join("\\u0027");
r = r.split('"').join("\\u0022");
return r;
}
return s;
}
var textoTodoErrado = "Sentes \"sede\"?\nQuero um copo d'água";
var s = '<a href="javascript:alert(\'' + escapeForLink(textoTodoErrado) + '\')">Clique aqui href</a><br/>';
s += '<a href="javascript:void(0)" onclick="alert(\'' + escapeForLink(textoTodoErrado) + '\')">Clique aqui onclick</a>';
document.writeln(s);
Com essa função os problemas de escape para passagem de parâmetro de texto em funções executadas apartir de links fica resolvido.

Um comentário: