Arquivos da categoria: HTML5

O que é: SPA – Single Page Application e REST/RESTFul

SPASPA – Single Page Application é uma novo modelo de desenvolvimento de aplicações Web e mobile que vem ganhando destaque em grandes empresas como Microsoft, Google, Twitter, Facebook, etc.

SPA basicamente significa codificar menos no server-side e mais no client-side. Ou seja, a aplicação estará contida toda ou quase toda no cliente (dentro do navegador Web). É praticamente uma aplicação Desktop rodando sob o navegador.

Vantagem:

1 – balanceamento da responsabilidade da execução entre cliente e servidor (agora não é só mais responsabilidade do servidor);
2 – menos código do servidor, e mais responsabilidade no cliente;
3 – melhorar a experiência ao usuário (UX) criando interface com usabilidade moderna e de fácil entendimento do usuário;
4 – menor consumo de banda, pois as cargas de dados são feitas por demanda e por AJAX.

O grande ator de app SPA é o código Javascript executado no cliente. Toda a aplicação pode ser construída simplesmente manipulando o DOM – Document Object Model de forma nativa, ou com o uso de bibliotecas e frameworks Javascript que auxiliam na construção da aplicação. Estas bibliotecas e frameworks fornecem recursos para manipulação dinâmica do DOM, definição de templates de tela, chamadas assincronas ao servidor, organização do código Javascript, etc. Dentres as diversas bibliotecas JS que surgem a todo momento, as mais difundidas na comunidade de progamadores estão: BACKBONE, EMBER, ANGULARJS e KNOCKOUT.

No lado servidor, temos a execução das linguagens tradicionais como PHP, ASP.NET, JSP, etc, trabalhando também de forma tradicional, servindo arquivos, acessando a banco de dados, tratando as regras de negócios que não podem estar no código JS por questões de segurança. E é neste lado (servidor) que podemos utilizar a arquitetura REST – Representational State Transfer para fornecer serviços do servidor para nossa aplicação SPA. É comum encontrar aplicação SPA utilizando serviços RESTFul. Uma aplicação no servidor que utiliza a arquitetura REST para servir serviços, então é chamada de RESTFul.

Ao construir uma aplicação utilizando a arquitetura REST, o protocolo HTTP é usado em sua essência, utilizando os verbos (ou métodos de requisição ao servidor): GET, POST, PUT e DELETE (estes são os mais comuns), e cada um deles indica uma determinada ação a ser executada em um recurso específico do servidor.

  • GET: Está requisitando ao serviço um determinado recurso, por exemplo, uma listagem de dados;
  • POST: Indica ao serviço que a ele deve receber o recurso que está sendo enviado e adicionar em algum repositório;
  • PUT: Indica que ao serviço que o recurso que está sendo enviado deve ser alterado se ele já existir, ou ainda, pode ser adicionado caso ele ainda não exista;
  • DELETE: Indica que o serviço deve excluir o recurso.

Pensando em banco de dados, temos o seguinte entendimento:

  • GET: Recupera dados [select];
  • POST: Realiza a inserção de dados [insert];
  • PUT: Realiza a alteração de dados [update];
  • DELETE: Realiza a exclusão de dados [delete].

AngularJS – Rotas

pic_angularOlá pessoal. Dando continuidade ao meu estudo sobre o angular, agora vamos de rota.

Numa aplicação SPA – Single Page Application usando o AngularJS, a navegação entre as views da app ocorrem sem requisições ao servidor, e baseada em rotas interna da própria app.

Para criar rotas em nossa app, o cenário perfeito é ter um arquivo principal de configuração. Por exemplo: app.js:

//criando um módulo global app com dependência ao pacote ngRoute
var app = angular.module('app', ['ngRoute']);

//definindo as rotas
app.config(function ($routeProvider, $locationProvider) {

    // remove o # da url, padrão
    $locationProvider.html5Mode(true);

    $routeProvider.when('/', { templateUrl: '/Views/lancamentos.html' });

    $routeProvider.when('/index.html', { templateUrl: '/Views/home.html' });

    $routeProvider.when('/lancamentos', { templateUrl: '/Views/lancamentos.html'});

    $routeProvider.when('/tp-lancamento', { templateUrl: '/Views/tp-lancamento.html'});

});

O objeto $routeProvider em seu método WHEN faz o registro da rota, sendo o primeiro parâmetro a rota de fato e o segundo, um objeto literal indicando da propriedade templateUrl o destino da rota. Por exemplo, toda chamada da app que ocorrer para “/lancamentos”, o conteúdo apresentado será o contido em “/Views/lancamentos.html”.

O link HTML para chamar o conteúdo da rota ficará assim:

<ul>
    <li><a href="lancamentos">Lançamentos</a></li>
    <li><a href="tp-lancamento">Tipos de Lançamento</a></li>
</ul>

O resultado do redirecionamento é o conteúdo do arquivo HTML referenciado pela rota. Este conteúdo deve ser depositado num contêiner que é marcado pela diretiva ng-view.

Exemplo:

<head>
    <script src="angular.min.js"></script>
    <script src="angular-route.min.js"></script>
    <script src="app.js"></script>
    <script src="Controllers/tpLancamento.js"></script>
    <script src="Controllers/lancamentos.js"></script>
</head>
<body>
   <ul>
       <li><a href="lancamentos">Lançamentos</a></li>
       <li><a href="tp-lancamento">Tipos de Lançamento</a></li>
   </ul>
   
   <div ng-view>
       <!--Conteúdo da view será carregado aqui--> 
   </div>
</body>

No código acima, observe a importação do arquivo “angular-route.min.js” responsável por manter o pacote ngRoute, utilizado no app.config. Também foi importado o arquivo app.js e os controladores para views.

AngularJS – Diretivas

pic_angularOlá pessoal. Dando continuidade ao meu estudo sobre o angular, deixo aqui registrado o que estudei e entendi sobre diretivas.

Diretivas dão poder ao programador para estender/ampliar o comportamento de elementos HTML, e é responsável pela manipulação do DOM. Uma diretiva é capaz de selecionar um elemento HTML por seu atributo (associado ao nome da diretiva), ou nome do elemento, ou por um comentário, ou mesmo pelo valor do atributo class.

Ao selecionar um elemento HTML, a diretiva pode ampliar seu comportamento, adicionando um novo HTML, manipulando o DOM, ou ainda associando eventos à funções Javascript.

São diversas as diretivas nativas do angular: ng-controller, ng-model, ng-repeat, ng-show, ng-hide, ng-click, ng-blur, ng-change, ng-checked, ng-focus, ng-keydown, ng-keypress, ng-keyup, e diversas outras.

Podemos criar nossas próprias diretivas (Custom Directives), para por exemplo:

    • Criar componentes como: abas, janelas de mensagens, janelas pop-up, calendário, etc…;
    • Intercecptar a vinculação de dados e tratá-los se necessário;
    • Criar uma esquema padronizado para validação do model;
    • Tratar eventos dos elementos HTML;
    • Etc…

Uma diretiva customizada deve estar associada a um módulo, podendo ser o próprio módulo da página:

<body ng-app="myApp">
    <div minha-diretiva></div>
</body>
var app = angular.module('myApp', []);

app.directive('minhaDiretiva', function () {
   return {
	restrict: 'A',
	link: function (scope, elem, attrs) {
		elem[0].innerHTML = "minha diretiva....";
	}
   }
});

No exemplo acima, a função directive() do módulo, é usada para criar uma diretiva chamada “minhaDiretiva”, retornando um objeto literal com suas definições. A propriedade restrict é usada para especificar como a diretiva irá selecionar o elemento HTML. Os valores válidos para restrict são:

  • ‘A’ – Atributo:
  • ‘E’ – Elemento:
  • ‘C’ – Class:
  • ‘M’ – Comentário:

A propriedade link deve ser associada a uma função de ligação que faz o trabalho de definição da diretiva. Parâmetros da função: scope, elem e attrs.

  • scope: dá acesso ao escopo da diretiva;
  • elem: é um objeto JQuery Lite contendo o elemento encontrado pela diretiva;
  • attrs: é um objeto que mantém todas as propriedades do objeto encontrado pela diretiva.

O resultado final após a execução da diretiva é:

<div minha-diretiva="">minha diretiva....</div>

Agora vou alterar a diretiva anterior para localizar elementos HTML pelo nome (customizado) da tag do elemento. Com angular, posso criar meus tipos de elemento HTML e definir seu comportamento.

<body ng-app="myApp">
    <minha-diretiva></minha-diretiva>
</body>
var app = angular.module('myApp', []);

app.directive('minhaDiretiva', function () {
   return {
	restrict: 'E',
	link: function (scope, elem, attrs) {
		elem[0].innerHTML = "minha diretiva....";
	}
   }
});

O resultado final é:

<minha-diretiva>minha diretiva....</minha-diretiva>

Observação: é padrão no angular o nome da diretiva seguir a nomenclatura: “primeira palavra iniciando em minusculo e demais com inicial maiúscula”, por exemplo: minhaDiretiva, janelaMensagem, etc. No momento de usar (no HTML) fica assim (dash-delimited): minha-diretiva, janela-mensagem, etc.

Utilizando o conceito de diretivas, também é possível criar templates utilizando as propriedades template ou templateUrl do objeto de retorno de definição da diretiva.

Avançando um pouco mais, mas nem tanto. Uma diretiva também pode ser um template. Observe:

<span meu-template="meu primeio template...">
app.directive('meuTemplate', function () {

    return {

        restrict: 'A',
        scope: {},
        link: function (scope, elem, attrs) {
            scope.msg = attrs.meuTemplate;
        },
        template: '<div><strong>{{msg}}</strong></div>',
        replace: false
    }
});

Ao usar a diretiva acima, obtém-se o seguinte resultado após a renderização:

<span meu-template="meu primeio template...">
    <div>
	 <strong>meu primeio template...</strong>
   </div>
</span>

O conteúdo da propriedade template da diretiva foi incluído dentro do elemento span selecionado pela diretiva. Isso ocorreu devido a propriedade replace estar configurada como false. Se configurado com true, o elemento span é totalmente substituído pelo conteúdo do template, observe o resultado da renderização:

<div meu-template="meu primeio template...">
   <strong>meu primeio template...</strong>
</div>

Há também no objeto de definição da diretiva para elementos (restrict: ‘E’) uma propriedade chamada transclude, que é capaz e anexar/incluir elementos (do contêiner selecionado pela diretiva) dentro do template da diretiva.

E para finalizar, segue um exemplo (simplório) de diretiva para mostrar áreas de mensagens.

app.directive('msgAlert', function () {

    return {
        restrict: 'A',
        scope: { textoMsg: '@'},
               
        template: '<div class="msgAlert">{{textoMsg}} <input type="button" value="(fechar)" ng-click="esconder()" /></div>',
        replace: true,
               
        link: function (scope, elemento, attrs) {
            scope.esconder = function () {
                scope.$parent.mostrarAlert = false;
            }
        }
    };
});

<style>
    .msgAlert {
        background-color:#ffd800;
        border: 1px solid #808080;
        padding: 5px;
        margin: 5px;  
   }
</style>

<div msg-alert texto-msg="{{msg}}" ng-show="mostrarAlert"></div>
<input type="button" value="mostrar alerta" ng-click="abrirAlert()" />

Conclui que usar diretivas não é tão fácil. :-(

Validações customizadas com HTML5

HTML5_Logo_512Quando as validações prontas do HTML5 não são suficientes, temos que fazer as nossas.

Em HTML5 temos um novo evento, oninput,  que pode ser associado a um input, e é disparado quando seu valor é modificado. Seu disparo deve ser associado a uma função Javascript para fazer a validação do valor informado no input.

Na função de validação o método setCustomValidity do input recebe uma string. Se vazia, significa que o dado está válido, caso contrário, o navegador mostrará a mensagem informada ao método.

Vamos a um exemplo:

&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; /&gt;
    &lt;title&gt;&lt;/title&gt;
    &lt;script&gt;

        function validaCPF(input){

            if (input.value.length &gt; 11 || input.value.length &lt; 11)
                input.setCustomValidity('CPF inválido');
            else input.setCustomValidity('');

        }

    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;form&gt;

            CPF:
            &lt;input type=&quot;text&quot; id=&quot;cpf&quot; name=&quot;cpf&quot; oninput=&quot;validaCPF(this)&quot;&gt;
            &lt;input type=&quot;submit&quot; id=&quot;enviar&quot; name=&quot;enviar&quot; value=&quot;Enviar&quot;&gt;
    &lt;/form&gt;
&lt;/body&gt;

 

Se seu querido navegador der suporte ao novo evento, algo como mostrado na imagem abaixo deve aparecer.

evento_oninput

 

 

Simples e eficiente.

CSS3: font-face

css31Um problema comum no desenvolvimento de um site é a tipografia (tipo da fonte). É normal o uso de fontes comuns (Arial, tahoma, verdana, etc), que existem nos sistemas operacionais dos diversos dispositivos capazes de executar um website.


font-family: Arial, Verdana, Sans-Serif;

Caso a fonte não exista, o navegador tenta assumir uma próxima fonte que foi definida no CSS (font-family). E se também não encontrar, o navegador vai assumir sua fonte padrão, o que pode “estragar” toda aparência do site.

Com CSS3 conseguimos forçar o navegador a baixar uma fonte caso ela não exista no sistema operacional do dispositivo. Isso pode ser implementado com o uso da diretiva @font-face, e é suportada somente nos navegador mais modernos (IE 9, Firefox, Opera, Chrome e Safari). A fonte deve estar disponível em algum servidor, que pode ser o do próprio site.

A especificação do W3C (http://www.w3.org/TR/css3-fonts/) relaciona os seguintes formatos de fontes suportados pelo font-face:

String Font Format Common extensions
“woff” WOFF (Web Open Font Format) .woff
“truetype” TrueType .ttf
“opentype” OpenType .ttf, .otf
“embedded-opentype” Embedded OpenType .eot
“svg” SVG Font .svg, .svgz

O diretiva @font-face deve estar dentro do arquivo CSS do site:


@font-face {
  font-family: 'Open Sans';
  src: local('Open Sans Light'),
       local('OpenSans-Light'),
       url(http://themes.googleusercontent.com/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTXhCUOGz7vYGh680lGh-uXM.woff) format('woff');
}

body { font-family: 'Open Sans', Arial, Verdana, Sans-Serif; }
}

Na diretiva @font-face as propriedades especificão:

  • font-family: o nome a a ser usado na regra font-family dos elementos HTML (no exemplo foi aplicado ao body).
  • src: a origem da fonte, sendo que primeiro será procurada localmente (local(‘..’)) no sistema operacional uma fonte com o nome ‘Open Sans Light’, se não encontrar vai procurar ainda localmente (local(‘..’)) um fonte como o nome ‘OpenSans-Light’, e caso não entre localmente, baixará a fonte no servidor informado em url(…). No exemplo acima a fonte está disponível no servidor do Google, mas poderia estar no próprio servidor do site.

Antes de fazer o font-face, é  necessário verificar a licença da fonte para não ter problemas de uso indevido.

Mais detalhes em:

Até mais.

WebWorkers

HTML5_Logo_512A execução de código Javascript é feita somente usando uma thread pelo navegador cliente. O navegador nunca vai executar dois eventos ao mesmo tempo. Funcões Javascript que tem execução mais longa travam a interface com o usuário até que termine sua execução.

As aplicações Web podem rodar melhor se as partes do código Javascript que exigem maior processamento fossem separadas em mais threads.

Execute dentro de uma página o código Javascript abaixo que simula um processamento demorado e tente usar a interface da página. Tudo estará travado, até que a execução do código termine.


function execucaoDemorada(){

    var tempoDeEspera = 10000; //10 segundos
    var inicio = (new Date()).getTime();
    var i = 0;
    while(((new Date()).getTime() - inicio) &lt;= tempoDeEspera){
        console.log(i);
        i++;
    }
}

Em HTML5 é possível usar Web Workers, que dá poder ao Javascript em executar thread paralelas sem bloquear/travar a interface com o usuário.

Um WebWorker não deve ser usado para operações triviais, e sim para operações complexas e longas:

  • Codificação/decodificação de uma sequência grande;
  • Cálculos matemáticos complexos (por exemplo, números primos, criptografia, simulados, algoritmos de reconhecimentos, etc);
  • Classificando uma grande variedade de dados;
  • Solicitações de rede e processamento de dados;
  • Cálculos e manipulação de dados sobre o local/sessionStorage;
  • Algoritmo de verificação/checagem de sintaxe ou análise outro texto em tempo real (por exemplo, a verificação ortográfica);
  • Manipulação de Imagem;
  • Analisar ou processar vídeo ou dados de áudio (incluindo face e reconhecimento de voz);
  • Processamento de matrizes de grandes dimensões ou respostas JSON enormes;

Um worker nada mais é que um script que irá ser carregado e executado em segundo plano, por exemplo:


var wk1 = new Worker(&quot;worker1.js&quot;);

A função construtura Worker() recebe por parâmetro uma URL especificando o arquivo contendo o código Javascript que será tratado em um nova thread,

O código javascript contido no arquivo carregado pelo worker não tem acesso ao objeto Window, Document e a árvore DOM da página que iniciou sua execução.

A comunicação entre o worker e a página ocorre através de mensagens. Objeto gerado pela classe Work oferece o método postMessage(). É ele que vai enviar solicitações da página para o código dentro do workers.  Além de enviar string, oferece envio de mensagens no no formato JSON. E as mensagens de retorno podem ser capturada associando uma função ao evento  do objeto worker criado.


//Código na página.

var wk1 = new Worker(&quot;worker1.js&quot;); //Criando o worker

//Monitorando as mensagens de retorno.
wk1.onmessage = function (e) {
    if (e.data.acao == &quot;mostrar&quot;)
        document.getElementById(&quot;incrementos&quot;).innerHTML = e.data.incremento;
    else if (e.data.acao == &quot;parar&quot;)
        wk1.terminate();
};

//É aqui que começa a execução do worker
wk1.postMessage(&quot;executar&quot;);

O evento onmessage fica monitorando as mensagens vindas worker para página. A função que vai tratar o evento recebe um parâmetro que possui uma propriedade data que contem a mensagem enviada pelo worker. No exemplo acima, o retorno a mensagem de retorno do worker é um objeto JSON.

O código contido no arquivo (do worker) também tem um evento onmessage e deve ter uma função associada, mas aqui é o worker que vai ficar escutando a página. Quando o método postMessage() na página é usado, é a função onmessage do worker que captura a mensagem que também é acessada pela propriedade data do parâmetro da função.

Para o worker enviar uma mensagem para a página, é também através do método postMessage().


//Código do worker.

// Evento que monita mensagens vindas da página para o worker
onmessage = function (e) {

    //e.data contém o valor enviado pela página.
    if (e.data === &quot;executar&quot;) {

        execucaoDemorada();

        postMessage(&quot;fim&quot;);
    }
};

function execucaoDemorada(){

    var tempoDeEspera = 10000; //10 segundos
    var inicio = (new Date()).getTime();
    var i = 0;
    while(((new Date()).getTime() - inicio) &lt;= tempoDeEspera){
        postMessage({ &quot;acao&quot;: &quot;mostrar&quot;, &quot;incremento&quot;: i }); //envia uma nova mensagem para a página
        i++;
    }
    postMessage({ &quot;acao&quot;: &quot;parar&quot;}); //envia uma nova mensagem para a página
}

Uma boa prática é fazer a liberação da thread na página pelo método terminate() do próprio objeto worker.

Outra informação importante é a possibilidade de ter páginas auto-suficiente, ou seja, o código a ser executado numa nova thread pode estar nela mesmo, sem a necessidade de separar num novo arquivo Javascript.

Até mais e baixe o exemplo aqui.

Introdução ao JSON – Javascript Object Notation

json160JSON é um formato para troca de dados baseado em estruturas de texto, o que lhe dá a característica de ser completamente independente de linguagem. É a mesma ideia do XML, só que mais simples e leve.

No site oficial (http://www.json.org/) o autor ainda afirma:

Para seres humanos, é fácil de ler e escrever.
Para máquinas, é fácil de interpretar e gerar.

A forma simples de representar dados no formato JSON tem difundido seu uso, e vem se tornando uma alternativa ao XML para implementações AJAX.

Em JSON podemos estruturar dados em (1) coleções de pares de nome e valor e também em (2) lista/array ordenadas de valores.

Os valores dos dados são representando em três formas: object, value e array, e ainda podem ser combinadas.

Object: é um conjunto de pares de nome/valores. A sintaxe de um object é


{ "nome da propriedade" : "valor da propriedade" }

O object começa com { e termina com }. E cada par de nome/valores é separado por ,(vírgula), sendo que os valores podem assumir diferente tipos de dados. Exemplo:


{“nome” : “Bill”, “idade” : 32, “salario”: 121232.67}

Array: é uma coleção de valores ordenados. A sintaxe de um array JSON é:


[ "valor1",  "valor2", "valor3" ]

O array começa com [ e termina com ], e cada parte  é separa por , (vírgula) e podem divergir o tipo de dados. Exemplo:


["Huguinho","Zezinho","Luizinho", 3]

Tanto a estrutura object como o array do JSON podem ser combinadas, formando diversas estruturas de dados.

Exemplo – Um array de objects:


[{ "nome" : "Huguinho", "idade" : 10 },
 { "nome" : "Zezinho", "idade" : 12 },
 { "nome" : "Luizinho", "idade" : 10 }]

Exemplo – Object contendo uma propriedade array:


{"tio" : "Pato Donald",
 "idade" : 40,
 "sobrinhos" :
        [{ "nome" : "Huguinho",     "idade" : 10 },
          { "nome" : "Zezinho", "idade" : 12 },
          { "nome" : "Luizinho", "idade" : 10 }]
}

JSON nasceu com um subconjunto da linguagem Javascript para representar objetos e atualmente qualquer linguagem de programação moderna tem suporte (via pacotes de terceiros) a esse formato de troca de informação.

Os sites jsonviewer.stack.hu e  jsonformatter.curiousconcept.com/ são bons lugares para validar a estrutura JSON

Num futuro post demonstrarei o uso do JSON com ASP.NET em chamada assíncronas.

Drag and drop (Dnd) com HTML5

hrml5draganddropUm recurso bacana que é visto em alguns site é o recurso de selecionar um item e arrastá-lo para outra área na mesma página. Este recurso é chamado de Drag and drop, e no HTML5 ele é nativo, dispensando o uso de bibliotecas de terceiros.
Para iniciar, precisamos definir um elemento HTML como “de origem” que será o elemento arrastável, e um elemento de destino, que receberá o elemento de origem.
O elemento HTML que deseja ser arrastável deve manter a propriedade draggable habilitada (true).
Por exemplo, desejo que cada item da lista abaixo seja arrastável:
&lt;ul id=&quot;ulOpcoes&quot;&gt;
    &lt;li draggable=&quot;true&quot;&gt;Opção 1&lt;/li&gt;
    &lt;li draggable=&quot;true&quot;&gt;Opção 2&lt;/li&gt;
    &lt;li draggable=&quot;true&quot;&gt;Opção 3&lt;/li&gt;
    &lt;li draggable=&quot;true&quot;&gt;Opção 4&lt;/li&gt;
    &lt;li draggable=&quot;true&quot;&gt;Opção 5&lt;/li&gt;
    &lt;li draggable=&quot;true&quot;&gt;Opção 6&lt;/li&gt;
&lt;/ul&gt;
Um elemento arrastável (draggable=true) tem os seguintes eventos:
  • dragstart: O elemento começou a ser arrastado. A função que vai tratar o evento recebe um parâmetro, que há uma referência ao elemento sendo arrastado.
  • drag: O objeto está sendo arrastado.
  • dragend: A ação de arrastar terminou.

Esses eventos devem ser associados a uma função para tratá-los.

&lt;/span&gt;&lt;/div&gt;
&lt;ul id=&quot;ulOpcoes&quot;&gt;
    &lt;li draggable=&quot;true&quot; ondragstart=&quot;onDragStart(event)&quot;&gt;Opção 1&lt;/li&gt;
    &lt;li draggable=&quot;true&quot; ondragstart=&quot;onDragStart(event)&quot;&gt;Opção 2&lt;/li&gt;
    ...

Usando Javascript, podemos associar os eventos a cada LI, sem a necessidade de fazer manualmente como acima.

window.onload = function () {

    //Após a carga completa da página, cada LI é associado à função onDragStart.
    var lis = document.querySelectorAll(&quot;#ulOpcoes &gt; li&quot;);
    for (var i = 0; i &lt; lis.length; i++) {

        lis[i].addEventListener(&quot;dragstart&quot;, function (event) { onDragStart(event) });
    }
}

function onDragStart(event) {

    event.dataTransfer.setData(&quot;Text&quot;, event.target.innerHTML);
}

A função que vai tratar o evento ondragstart recebe um parâmetro, que há uma referência ao elemento sendo arrastado através da propriedade target. E a propriedade dataTransfer, com o uso do método setData, oferece meios de armazenar dados a serem transmitidos ao destino. O primeiro parâmetro da função setData é o tipo mime da informação a ser armazenada (no exemplo, Text) e o segundo parâmetro é a informação (no exemplo, guardei o texto contido dentro do LI). Posteriormente será o usado o tipo mime para recuperar a informação.

Com a origem totalmente programa, agora é hora de pensar no destino. O elemento de destino não precisa de nenhuma propriedade específica, como o de origem. Mas precisa de eventos e funções que saibam como receber o que foi arrastado até ele.

O elemento de destino tem os seguintes eventos:
  • dragenter: O objeto sendo arrastado entrou no objeto de destino.
  • dragleave: O objeto sendo arrastado deixou o objeto de destino.
  • dragover: O objeto sendo arrastado se move sobre o objeto de destino.
  • drop: O objeto sendo arrastado foi solto sobre o objeto de destino.

Neste exemplo, o elemento de destino será outra lista, que deverá receber o texto do item da lista de origem que foi arrastado até ela.

&lt;ul id=&quot;ulOpcoesSelecionadas&quot; ondragover=&quot;onDragOver(event)&quot; ondrop=&quot;onDrop(event)&quot;&gt;
&lt;/ul&gt;

O evento ondrop será o responsável por tratar e receber o item arrastável. A função associada ao evento recebe por parâmetro informações sobre o destino, e também a informação guardada na propriedade dataTransfer armazenada anteriormente sob o tipo mime. O método getData precisa do tipo mime armazenado para poder recuperar a informação (como no exemplo a seguir, Text).

function onDrop(event) {
    var li = document.createElement(&quot;li&quot;)
    li.innerHTML = event.dataTransfer.getData(&quot;Text&quot;);
    document.getElementById('ulOpcoesSelecionadas').appendChild(li);
}

E por fim, para que tudo funcione corretamente, é necessário mudar o comportamento padrão do navegador. Por padrão, dados/elementos não podem ser soltos em outros elementos. Para permitir um “drop”, devemos mudar o tratamento padrão do elemento de destino.

E isso é feito na função que trata o evento ondragover do elemento de destino, que é disparada quando o objeto sendo arrastado se move sobre o objeto de destino.

function onDragOver(event)
{
    event.preventDefault();
}

O evento envia a função informações sobre o destino, e o método preventDefault() do parâmetro cancela o comportamento padrão do navegador, e assim permitindo o drop.

O exemplo completo e com exemplos de uso de todos os eventos pode ser baixado aqui.

E é isso….

 

Até mais.

Usando a API WebStorage da Open Web Plataform (HTML5 e seus amigos)

HTML5_Logo_512Em HTML5 é possível armazenar dados no lado do cliente no formato pares de valor de chave, de forma simular como é feito com as Cookies, só que mais fácil. Normalmente é a linguagem de servidor quem cria e envia as Cookies ao cliente.
Com a API de Storage tudo é manipulado diretamente no cliente por Javascript, não há interferência do servidor.
A API WebStorage disponibiliza duas formas para armazenamento no cliente: SessionStorage e LocalStorage.

sessionStorage
: armazenamento de dados independente (não compartilhado entre janelas/guias). Os dados são excluídos quando o usuário fecha a janela/guiado navegador.

localStorage: armazenamento de dados compartilhado entre janelas (comportamento semelhante ao do cookie). Mesmo fechando o navegador, os dados ficam armazenados e somente serão apagados se o cache for limpo ou se solicitada sua exclusão via programação JS.

Vamos aos exemplos.
A ideia aqui é armazenar o que o usuário informou no formulário HTML abaixo usando as duas maneiras apresentadas acima, e depois recuperar a informação.
&lt;textarea id=&quot;texto&quot; rows=&quot;5&quot; cols=&quot;5&quot;&gt;&lt;/textarea&gt;
&lt;br /&gt;
&lt;input type=&quot;button&quot; value=&quot;Salvar no cliente&quot; onclick=&quot;salvar()&quot;/&gt;
&lt;input type=&quot;button&quot; value=&quot;Recuperar no cliente&quot; onclick=&quot;recuperar()&quot;/&gt;

O evento onclick do primeiro input button vai disparar a função salvar(), que tem por objetivo salvar os dados no cliente usando o método setItem da propriedade localStorage. Vamos ao código.

    function salvar() {
        localStorage.setItem('teste', texto.value);
    }

E evento onclick do segundo input button vai disparar a função recuperar(), que vai acessar o valor salvo através do método getItem da propriedade localStorage e devolvê-lo para seu respectivo input.

    function recuperar() {
        document.getElementByI('texto').value = localStorage.getItem('teste');
    }

Usando a Ferramenta de Desenvolvedores do Google Chrome é possível inspecionar o que está armazenado localmente.

localstorage

A nível de programação, para usar a SessionStorage não muda quase nada. Ao invés de usar a propriedade localStorage, deve usar sessionStorage. E os métodos setItem e getItem continuam com o mesmo objetivo, adicionar e remover valores.

Quando usado Cookie, ela é trafegada sempre entre cliente e servidor pelo protocolo HTTP. Isso não ocorre com esta API, a informação é exclusivamente mantida no cliente, e nunca “sobe” para o servidor.

Outros dois métodos importantes disponibilizados são o removeItem, e clear. O primeiro remove o item de nome informado no parâmetro e o segundo, limpa todos os itens do domínio. Ambos funcionam tanto no localStorage como no sessionStorage.

Usando a API de Geolocalização da Open Web Plataform (HTML5 e seus amigos)

HTML5_Logo_512A API Geolocation da Open Web Plataform  permite via Javascript solicitar ao navegador a localização real do usuário. As informações de localização podem ser usadas para exibir mapas, direções e outras informações relevantes a posição global do usuário.

Os navegadores que suportam a API definem a propriedade navigator.geolocation que oferece três métodos:

  1. navigator.geolocation.getCurrentPosition(): solicita a posição atual do usuário.
  2. navigator.geolocation.watchPosition(): solicita a posição atual do usuário e continua a monitorar.
  3. navigator.geolocation.clearWatch(): para de monitorar a posição do usuário.

Abaixo demonstro um pequeno exemplo de como recuperar a geolocalização do usuário e mostrar um mapa no Google e no Bing Maps com a respectiva localização do usuário.


//Usando do método getCurrentPosition para recuperar a localização atual do usuário.
navigator.geolocation.getCurrentPosition(function (posicao) { localizacao(posicao) },
            function (erro) { mostraErro(erro) });

//Função de Callback do sucesso do método getCurrentPosition
function localizacao(posicao) {
    alert('Lat: ' + posicao.coords.latitude + ' ' + 'Lon: ' + posicao.coords.longitude);

    //Abrindo o mapa no bing maps
    window.open(&quot;http://www.bing.com/maps/?v=2&amp;where1=&quot; + posicao.coords.latitude + &quot;,&quot; +
posicao.coords.longitude + &quot;&amp;encType=1&quot;,&quot;&quot;);

    //Abrindo o mapa no google maps
    window.open(&quot;http://maps.googleapis.com/maps/api/staticmap?center=&quot; +
posicao.coords.latitude + &quot;,&quot; + posicao.coords.longitude +
&quot;&amp;zoom=14&amp;size=400x300&amp;sensor=false&quot;);
}

//Função de Callback para falhas método getCurrentPosition
function mostraErro(erro)
{
    switch (erro.code) {
        case erro.PERMISSION_DENIED:
            alert(&quot;user did not share geolocation data&quot;);
            break;
        case erro.POSITION_UNAVAILABLE:
            alert(&quot;could not detect current position&quot;);
            break;
        case erro.TIMEOUT:
            alert(&quot;retrieving position timed out&quot;);
            break;
        default:
            alert(&quot;unknown error&quot;);
            break;
    }
}

Infelizmente não é exato pois, pois a API usa informações dos provedores de internet a qual o usuário está conectado.

E é isso. As possibilidades são várias.