Internacionalização de ficheiros de JavaScript

Os últimos posts no meu blog têm sido acerca do tema da internacionalização de aplicações, nomeadamente:

O post de hoje contínua o sobre o método alternativo com ASP.NET, recorrendo a ao GetText do GNU. Como vimos, a aplicação do método _() para substituir texto localizável tornava-se um recurso simples e eficiente na internacionalização de ASP.NET. Em especial, é um método adoptado pela restantes linguagens e evita o esforço extra necessário para introduzir o texto em ficheiros .resx.

Continue reading

Less.js – Less em javascript!

O Less é um framework de escrita de css que permite utilizar variáveis, herança e outros coisas giras. Mencionei-o há uns posts atrás, linkando as versões de ruby e .net. As versões que mencionei são construídos server-side. Actualemnte, o Less está a ser portado para javascript, permitindo a mesma funcioanlidade mas processado do lado do cliente. Este post refere essa evolução:

http://fadeyev.net/2010/06/19/lessjs-will-obsolete-css/

Outro framework do género a ver: Sass http://sass-lang.com/

FileUpload, iframes, e actualização de listas.

Andei à procura de uma solução para um problema de envio de ficheiros, e não estava a encontrar nas pesquisas uma solução válida, dentro do contexto que estava a desenvolver. Felizmente lembrei-me duma que resultou e que vou descrever. E até é bastante simples! lol…

Então o contexto. Tenho uma página complexa (tem imensos blocos de funcionalidade ortogonais). Um das secções / blocos representa um conjunto de documentos associados a uma entidade. A funcionalidade da página está bastante dependente de AJAX para evitar carregamentos de página e ter uma interface mais fluída. Porque o bloco de adição dos documentos requer um upload, queria que o upload também fosse efectuado sem refresh da página.

Aparentemente, não é possível fazer o envio directamente com uma chamada a um método por AJAX. A solução então passa por usar um iframe na página, e o conteúdo desse iframe ser um novo formulário de envio. Segui esse caminho – implementei o iframe e criei a página de upload (o formulário tem um control de Fileupload, uma DropDownList, e um botão de envio). Neste caso, a funcionalidade de upload está contido neste formulário e este é o único responsável pelo upload. e funciona correctamente como esperado. O postback é contido no formulário do iframe e apenas nesse ponto é que há refresh. E é aceitável.

O problema que surge agora é que na página original, tenho a lista de documentos associados à entidade, e necessito de actualizar essa lista com o novo documento associado. A minha lista de documentos é carregada por chamadas AJAX, usando os métodos de templates javascript que mencionei no penúltimo post e portanto bastaria chamar novamente a função que preenche a lista para conseguir actualiza-la. Procurei então um método de comunicação entre frames, para que o a acção de click do botão ou do refresh da página actuasse sobre a página pai. Má ou impossível solução. No entanto, no meio disto, lembrei-me – “bem, se cada vez q é feito um upload, há um postback e a página do iframe é recarregada, será que dá para simplesmente apanhar o evento de ‘load’ do iframe?”. E a verdade é que sim, sempre que a página do iframe é carregado, o load do iframe dispara. Assim, fiquei com :

$(document).ready(function() {
      $('#docuploadframe').bind('load', function() { LoadDocList(); });
 });

Conclusão: em cada upload de documento, o load do iframe é disparado (após upload, ou mesmo erro), e então recarrego a lista de documentos após esse evento, via AJAX. Simples!

display:inline-block .. tão útil!

Pois é, esta semana e a passada é a do frenesim das interfaces. Mas ainda bem. Resumindo, tive uma certa “infelicidade” em comprar os controlos da DevExpress. Ainda por cima comprei uma licença Enterprise. Não são de todo maus, mas na realidade conseguem ser bastante. Tipo, têm funcionalidade boa compactada no controlo, e o aspecto visual e funcionamento acaba por ser relativamente intuitivo para o utilizador final. O problema é a API (quer server quer cliente) que é demasiado complexo e muitas vezes nada intuitivo (o que me tem causado muiiiitoo tempo perdido e muitas dores de cabeça). A coisa que mais me chateia naquilo é o HTML que é renderizado… meu Deus.. TABELAS POR TODO O LADO!!! . Género, para desenhar um select box são necessárias mil tabelas encaixadas umas nas outras. É código feio, muito feio, e difícil depois de fazer o que quer que seja com Javascript e jQuery, porque simplesmente não sabes onde actuar (o menu da aplicação, renderizado no cliente, ocupava umas 1500 linhas de código – agora são 160, incluindo javascript, e consigo facilmente encontrar as coisas que preciso!). Os controlos tem todos uma API do lado cliente, mas até hoje ainda não percebi nada daquilo, e a documentação daquilo é fraquinho.

O bom é que o serviço de apoio é bom, e o CodeRush é um excelente produto, e esse recomendo sem dúvida. É um auxilio fantástico. Mas os controlos podem esquecer. A menos que o projecto seja muito simples, sem camadas e objectos e camadas e afins, (tipo o ui conectar-se à BD), aquilo acaba por dar muitas dores de cabeça. Mais fácil gerar código e fazer as interfaces à mão com HTML e controlos ASP.Net, e ainda combinar CSS com jQuery. é o que tenho feito ultimamente com o meu colaborador, e acredita, estou bem mais satisfeito, e acredito que tenho uma interface bem mais agradável e funcional. Caí um bocado no “hype” daquilo, e infelizmente, hoje ando a refazer interfaces e designs…

Portanto, agora, tenho criado umas interfaces bem mais limpas e bem mais funcionais. Ainda mantenho alguns dos controlos em locais em que não “estragam” nada e mantém funcionalidade válida. Mas onde possível e onde se justifica, estou a limpar. E como é claro, há uma série de coisas que estou a aprender às custas disso (e uma biblioteca de javascript com funcionalidade universal às interfaces, que tem sido muito útil).

Então uma revisão rápida às “coisas” aprendidas:

  • É possível criar templates do lado cliente para renderizar dados vindos em chamadas AJAX. Tenho testado duas formas, com bons resultados em ambos, sendo mais ou menos útil numa ou noutra situação. Um á muito boa quando a resposta AJAX é uma lista. Neste caso é a solução do script do tipo “text/html” com o template de renderização em html, e os campos a preencher em entre tags <#= #> (semelhante ao T4). É depois usado uma função javascript para correr o template e substituir o os campos com o resultado do pedido AJAX. O método está descrito no blog do Dan Whalin e ainda no do Rick Strahl. Recomendo uns testes. É muito rápido na execução (a latência é reduzida por haver poucos dados na transmissão) e é óptimo para soluções de paginação.O segundo método é o de ter uma div escondida, com a estrutura de apresentação dos dados e os campos bem identificados, e usar o clone() do jquery, para criar uma cópia do bloco, preenche-lo, e apresentar no local onde necessitar. O clone é opcional e depende do que é pretendido, mas é uma solução muito útil para apresentar detalhe e blocos de inserção / edição. E é facil de implementar e perceber. Arisco dizer mais fácil que soluções compradas…Sério.
  • JSON é fantástico. Dados bem estruturados e que ocupam muito pouco espaço. Muito menos que XML. Diria mais limpo, até. Mas não é um mar de rosas total. Por exemplo, a serialização de Datas é muito estranho, porque a data é em si uma estrutura de dados complicado de representar. Alías, no javascript, tens uma forma única que é através do construtor “new Date()”. Problema é que JSON é transmitida como texto e a deserialização dá barraca.Solução? O serviço .NET envia uma string do tipo “/Date(1241796300465)/” O numero no interior com 13 digitos, representa o numero de milisegundos desde 1 de Janeiro de 1970, até à data ali representada. para transformar isso, nada como um pouco de código Javascript:
    function GetJSDateFromNET(netDateString) {
       var myregexp = /\d{13}/;
       var match = myregexp.exec(netDateString);
       if (match != null) {
          result = match[0];
       } else {
          result = "";
       }
    
       var foo = new Date(parseInt(result));
       return foo;
    }
    

    Assim, procuro os 13 digitos via regex, e crio a data a partir do número no encontrado, que é efectivamente suportado pelo construtor de Datas do javascript. Também evito um eval que poderia ser de alguma forma perigosa, imagino.

  • Prototypes. Muito bom! Melhora a escrita no javascript permitindo encadear funções de instâncias (métodos), e extender as funcionalidades de tipos basicos como strings, inteiros e datas. Já tinha visto, mas nunca tinha percebido ou notado o potencial. Agora, sim. Por exemplo, para a função anterior, já posso aplicar uma função directamente ao tipo string para criar a data, e se quiser, encadiar uma transformação para string formatada:
    msg.d.CampoDeDataDoJSON.toDateJsonNet().toYMDString();

    que resultaria numa string com o formato “yyyy-MM-dd”. Para isso tenho:

    String.prototype.toDateJsonNet = function() { return GetJSDateFromNET(this); }
    
    function DateToYMDString(date) {
        return date.getFullYear() + "-" + (date.getMonth() + 1).toString().lpad('0', 2) + "-" + date.getDate().toString().lpad('0', 2);
    }
    
    Date.prototype.toYMDString = function() { return DateToYMDString(this);}

    De uma forma simples, o prototype acrescenta funcionalidade ao tipo (aqui é com um tipo de dados base, mas podia ser um tipo que eu criei). Também te deixa o código mais limpo e legível, o que é sempre importante!

  • display:inline-block. Esta é fantástica. E resolve um problema “clássico” de colunas, sem recorrer a tabelas nem floats. Tem algumas manhas, e dependências de browsers que aplicam incorrectamente (mais IE hacks, mas simples), e bem explicadas aqui, aqui, e aqui. Para o meu caso quero duas colunas, lado a lado, baseados em divs.
    ...
    ...
    .col1{width:70%; display:inline-block; vertical-align:top;*display:inline;*zoom:1}
    .col2{width:29%; display:inline-block; vertical-align:top;*display:inline;*zoom:1 }

    O segredo está na combinação “display:inline-block” com “vertical-align:top;” o primeiro permite colocar divs lado a lado, mas verticalmente ficam alinhados pela base do texto contido nas divs. para isso, serve o vertical-align:top. Isto funciona bem no FF3.5. Para resolver para IE8, basta o “hack” do asterisco como prefixo no display:inline e zoom:1, que são interpretados apenas pelo IE. Apenas testei no IE8 (que é o q necessitava) e resulta bem. O que mais gosto disto é que a div que suporta as duas colunas 8um género de contentor clássico para centrar tudo) cresce quando qualquer das duas colunas cresce, o que não acontece com as soluções de float, como tinha anteriormente. Esta fui uma bela revelação para mim, que já tive este problema diversas vezes!

E por hoje chega. Ficam assim aqui algumas das fantásticas revelações destas semanas!!! :D

Ler um DateTime, passo por JSON, com Javascript

O título é algo confuso, mas o problema é pertinente. Quando se utiliza JSON para transmitir dados entre servidor e browser-cliente, enquanto a generalidade de objectos serializáveis são convertidos correctamente (um inteiro é um inteiro, uma string é uma string…), os valores de datas não são convertidos como um tipo Date do javascript, nem DateTime do .NET. A generalidade dos valores passos no JSON são convertidos para uma forma literal correspondente – os números numa sequência de caracteres numéricos, as strings como sequência de caracteres, etc. Mas para o tipo que representa uma data, simplesmente não existe um literal único – basta pensar que há dezenas de formas de representar uma data – só a parte do calendário, ou com hora, ou com variações de barras e hifens, ou com a troca de texto e ordem com base em culturas variadas.

Na serialização JSON do .NET, a Microsoft decidiu adoptar uma convenção para enviar os dados num formato literal – a data é representada pelo número de milissegundos desde a data de referência de 1 de Janeiro de 1970. O formato em que é enviado é:

/Date(xxxxxxxxxxxxx)/

Evidentemente, esta string não é uma data por si só, apenas uma representação literal (e independente de constrangimentos culturais). Necessitamos de converter os ticks numa data. No javascript o único método de conversão que temos é a função Date(), que funciona como construtor do objecto da Data. Dos vários overloads que existem, há um que recebe o número de milisegundos desde 1 de Janeiro de 1970, tal como o número que recebemos da resposta JSON!

Sendo assim, podemos usar a seguinte função para obter a estrutura da Data, a partir do literal devolvido pelo servidor:

function GetJSDateFromNET(netDateString) {
    var myregexp = /\d{13}/;
    var match = myregexp.exec(netDateString);
    if (match != null) {
        return new Date(parseInt(match[0]));
    } else {
        return null;
    }
}

Assim, com o valor devolvido pode-se fazer algo do género:

...
var data = GetJSDateFromNET(valorDataJSON);
alert(data.getYear());
...

A função, reutilizável, permite ler correctamente o literal de data enviado pelo servido, e processar a data do lado do cliente.

referencias:
An Introduction to JSON @ MSDN
Encosia

Sapo Maps e a API

Comecei há uns dias a desenvolver uma pequena app com mapas, que é uma área em que ainda não tinha feito qualquer teste. A app é muiiito simples, e apresenta as posições de navios nos portos no território marítimo nacional, com base em pontos obtidos por um receptor próprio. Lol, é em troca de um pequeno vício meu – revistas PHOTO.

Anyway, aquilo baseia-se em mapas e API do Google. Na verdade, a API é bastante simples, e o volume de exemplos permite desenvolver coisas muito rápidamente. Mesmo que simples, ficam porreiros.

De qualquer forma, nos últimos dias, quem segue estas coisas deve ter visto pelo RSS que a Sapo renovou a sua API. Olhei para a aplicação dos mapas, e parece-me bastante interessante e rápida e com uma API tb bastante interessante. Ainda não acabei a outra, pelo que secalhar vou experimentar usar também a da SAPO, para ver as diferenças e a funcionalidade permitida. Acredito que servirá perfeitamente para o que pretendo (e para uma outra ideia que tenho em mente, do género).

Para quem quiser experimentar:
http://mapas.sapo.pt

A API:
http://mapas.sapo.pt/api e http://mapas.sapo.pt/api/files/SAPOMapasAPI-CheatSheet.pdf

Até tem um documento sobre como passar do google maps e bing maps para os da SAPO. A ver!

PS. e com jeitinho isto amanha tá nos 100k, a tempo de celebrar no jantar do fim dos estágios.. lol

Uns tópicos para terminar o ano…

Pois é, o Natal já lá vai (e espero que tenha sido bom para todos) e o novo está por aí a vir. E como tal, o blog estava a merecer um postzito, pelo menos. Portanto, vai em jeito de rapidinha…

Javascript/Jquery e Master Pages

Uma das dificuldades em utilizar MasterPages em .Net é manter caminhos correctos nas referencias, especialmente se necessitas de reflectir esses caminhos em páginas de conteúdos ou controlos de utilizador não referenciados na mesma pasta que a master page. No caso de Javascripts, o caminho passa por usar o ScriptManager:

<asp:ScriptManager runat="server" LoadScriptsBeforeUI="true">
	<Scripts>
            <asp:ScriptReference Path="~/Scripts/jquery-1.2.6-vsdoc.js" />
            <asp:ScriptReference Path="~/Scripts/universal.js" />
        </Scripts>
</asp:ScriptManager>

Neste caso, o ScriptManager gere a inclusão dos tags de script na página. Por outro lado, também seria possível usar o método Page.ResolveUrl() para obter a referencia correcta do caminho.

Se for necessário uma referência no code behind, a solução apresentada no offroadcoder.com que utiliza o método RegisterStartupScript() do ScriptManager.

Sb2DevelopersBlog
A equipa de desenvolvimento da SB2 (francesa) mantém um blog (em inglês) muito muito com muitas amostras de código, como por exemplo o:

Entre muitos outros. É um feed a manter no RSS

Google Reader

E pro falar em RSS, decidi (e após muita insistência do Paulo Carrasco) começar a usar o Google reader, e verdade seja dita, até estou relativamente satisfeito. Gosto muito do GreatNews, mas o reader do Google está igualmente bom, e a partilha de posts é algo que representa uma mais valia.

os meus items partilhados estão em : http://www.google.com/reader/shared/03649456030336896792. Pode eventualmente haver pro lá umas coisas NSFW ligadas à fotografia… mas é principalmente programação.

E para já, tá se bem. Há tanto que poderia escrever, mas tem de ser aos bocadinhos. Tenho andado “a correr” com as tarefas e efim. é código + código + código… Bom Ano!

Javascript Debugger para IE

Uma das tarefas mais dificis que encontro é efectuar debug, especialmente ao javascript. Se bem que no Firefox o Firebug é uma ferramenta espectacular, as diferenças de interpretação de javascript entre browsers não resolver todos os problemas.

No caso da Microsoft, para o IE6/7 não há nada que se integre directamente no browser como o Firebug no Firefox. No entanto a Micrsoft tem efectivamente um debugger que geralmente vem o Microsoft Office que é o “Microsoft Script Debugger. É pequeno (um installer de 650K) e pode ser obtido em http://www.microsoft.com/downloads/details.aspx?FamilyID=2f465be0-94fd-4569-b3c4-dffdf19ccd99&displaylang=en. A ferramneta pode ser utilizado em conjunto com o Visual Studio (para debug de script cliente e de servidor) ou solitáriamnete.

Eu por exemplo necessitei para fazer um debug de um script numa máquina XP sem o Office. Além de ter instalado o Debugger, necessitei de habilitar o debugger no IE. As instalações são descritas em http://www.jonathanboutelle.com/mt/archives/2006/01/howto_debug_jav.html e http://www.my-debugbar.com/wiki/CompanionJS/HomePage.

E já agora, ao ver este ultimo link, aparece o Firebug Lite, a espelhar o Firebug do FF mas para IE, Opera e Safari. É baseado num ficheiro javascript a incluir na página a depurar e q sobrepõe um género de consola sobre a página! A ver, sem dúvida.