Observe a orientação do device com JavaScript

Com Javascript podemos observar a orientação do device, também é possível realizar este tratamento com CSS, mas isso fica restrito a questões visuais, caso queria realizar algum tratamento lógico em nossa aplicação podemos utilizar JavaScript. Temos “N” possibilidades de acompanhar a orientação do device, nesse post vou mostrar duas maneiras bem simples, a primeira observando o evento ‘orientationchange’, para isso adicionamos um listener em em nossa janela com o seguinte código:

 window.addEventListener('orientationchange', function(){
   	// faça alguma coisa
   });

O código acima acompanha quando a orientação do device muda, mas como sabemos que o usuário está em landscape ou portrait, para isso pegamos a orientação do device, com window.orientation essa propriedade retorna a rotação do device:

window.addEventListener('orientationchange', function(){
   	switch(window.orientation) 
    {  
      case -90:
      case 90:
        alert('landscape');
        break; 
      default:
        alert('portrait');
        break; 
    }
   });

Com as informações sobre a rotação do device sabemos que 90 ou -90 o device está em landscape e diferente disso portrait. No código acima foi disparado somente um alert, mas poderíamos chamar alguma outra função, editar uma classe de um elemento ou adicionar uma conteúdo específico para o usuário.

A segunda opção seria com matchMedia ela faz parte da Web API Interface com ela podemos validar media queries por exemplo:

if (window.matchMedia("(min-width: 360px)").matches) {
  /* O view port tem pelo menos 360px de largura */
} else {
  /* o view port tem menos de 360px de largura */
}

Podemos validar qualquer media query no CSS3 temos uma regra para  verificar a orientação vamos utilizar ela para pegar  o orientação do nosso device:

function handleOrientationChange(mediaQuerie) {
  	if (mediaQuerie.matches) {
    		alert("portrait")
  	} else {
    		alert("landscape")
  	}
}

/* Criamos uma variável para armazenar a media querie */
var mediaQuerie = window.matchMedia("(orientation: portrait)");

/* Adicionamos um listenr para acompanhar a mudança de orientação */
mediaQuerie.addListener(handleOrientationChange);

Temos ai duas opções para verificar a orientação do device.

Limites do LocalStorage

Sempre quando falo de localStorage as pessoas me perguntam: “Qual o limite do LocalStorage?” sempre respondia o valor padrão de 5MB, mas esse valor é apenas uma especificação da W3C. Segundo ela:

A mostly arbitrary limit of five megabytes per origin is suggested. Implementation feedback is welcome and will be used to update this suggestion in the future.

Ela sugere(não é obrigatório) que o espaço reservado por origem seja de 5MB e no futuro esse limite pode ser atualizado, a origem citada anteriormente no caso é por cada domínios. As variações a1.exemplo.com , a2.exemplo.com , a3.exemplo.com são considerada a mesma origem.

Em nosso caso o espaço disponível para o localStorage em aplicações em HTML5 na plataforma BlackBerry 10 é de 25MB, para armazenamento de texto 25MB é muita informação. Caso chegue ao limite do armazenamento será levantada uma exceção : QUOTA_EXCEEDED_ERR.

Caso queria saber o limite de armazenamento do seu browser, existe esse teste online: http://arty.name/localstorage.html

Segundo o site citado acima podemos modificar o limite de armazenamento no Opera, Firefox e no Chrome/Safari/IE

Crie accordion sem javascript

 

<details> é uma tag que podemos encapsular de desencapsular um determinado conteúdo, para obter informações adicionais sobre uma determinada informação, resumindo um accordion. Para trabalhar com esse recurso além da elemento <details>, precisamos do elemento <summary>, ele deve ser incluso como filho do <details>. Com este elemento conseguimos prover uma legenda ou um capítulo para o conteúdo restante, ele também será responsável por clicarmos nele e o conteúdo ser exibido.

O elemento <details> tem um atributo chamado open, ele define se o conteúdo será inicialmente visível ou não. Por default essa propriedade é false. Com esse recurso produz uma interatividade sem nenhum javascript.

Vamos ao código:

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title> Details </title>
	<style>
		details{
			border-radius:3px;
			padding:5px;

		}
		summary{
			border-radius:3px;
			border:1px solid #ddd;
			padding:5px;
			outline:none; 
		}

		details[open]{
			background:#ddd;
			border:1px solid #333;
		}
		details[open] summary{
			border:none;
		}
	</style>
</head>
<body>

<details open>
	<summary>Autor</summary>
	<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, nemo, dolores numquam fugit ipsum velit eaque repudiandae ea libero est.</p>
</details>

<details>
	<summary>Livros</summary>
	<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nulla, nemo, dolores numquam fugit ipsum velit eaque repudiandae ea libero est.</p>
</details>

<details>
	<summary>Jobs</summary>
	<p> Consequuntur, consequatur ut earum dolore placeat doloribus in voluptatem culpa.</p>
</details>
</body>
</html>

No código acima adicionei um CSS para dar um acabamento visual, nele vou fazer duas observações, o summary por default quando clicado exibe um highlight para remove-lo basta adicionar a propriedade “outline:none; “. A segunda observação é referente a como estilizar um item quando ele está ativo, para isso utilizamos o seguinte seletor “details[open]”. No código HTML o primeiro item tem a propriedade open setada assim ele inicia com seu conteúdo exibido. e o resultado será o seguinte:

 

Um recurso simples que economiza o uso de Javascript. O código desse tutorial você pode encontrar no meu gitHub no seguinte link: https://github.com/fellyph/Tutorial-bbUI/tree/master/details

Chame o card de SMS ou o card de discagem com um simples link

Você sabia que é possível preparar um envio de uma SMS via tag <a>. Isso é um recurso bem antigo(início de 2010) dos primórdios do HTML Mobile e podemos usar este recurso bem útil e otimizar a experiência do usuário, imagine uma listagem de lojas o usuário deseja ligar para uma loja específica, se não utilizar a tag <a> o usuário precisa copiar o texto, sair do browser e colar no discador. Mas para resolver isso com apenas um clique é bem simples:

<a href="sms:1234567?body=Hello BB10">Enviar um SMS via link</a>

Como podemos ver no código acima na propriedade href do nosso link iniciamos com “sms:” para indicar que vamos enviar um sms e o número na sequência 1234567 é o número o qual você quer enviar a mensagem. Depois utilizamos uma “?” para passar um segundo parâmetro o corpo da mensagem.

 

Outra opção é usar a tag <a> ligar para algum número específico, isso é possível com o seguinte código:

<a href="tel:1234567">Ligue já!</a>

Quando o usuário clicar no link, caso possua o Skype ele será invocado para fazer a ligação.

Caso queira baixo esses exemplos, eles estão no meu gitbub no link: https://github.com/fellyph/Tutorial-bbUI/tree/master/link/www

Utilizando localStorage para armazenar dados no Device

localstorage

No HTML5 uma features mais utilizada para aplicações móveis é o armazenamento local. Ou DOM Storage como é chamado, ele foi introduzido na especificação da Web Applications 1.0 depois também adicionada na especificação da W3C Web Storage. Com o DOM Storage podemos armazenar dados do usuário no device de forma fácil e segura, em comparação aos cookies, esse recurso era a única opção de armazenamento local sem o uso de plugin foi fortemente utilizado quando o HTML era somente para Desktop.

LocalStorage é um dos recursos do DOM Storage que vamos abordar nesse post, com ele podemos armazenar dados apenas em formato de texto, mas claro podemos contornar essa limitação. Vamos a um exemplo básico de armazenamento.

localStorage.setItem("device","BlackBerry");

No código acima adicionamos uma variável com nome “device” que irá armazenar a String “BlackBerry”. Para visualizar se a informação foi realmente salva, vamos em developer tools em seu browser ou no “debug mode” caso esteja “buildando” em seu device, depois Resources > LocalStorage e procuramos a informação device no painel. Como podemos ver na imagem abaixo:

Captura de Tela 2013-12-22 às 13.36.22

Agora que sabemos que a informação foi salva vamos resgatar esse valor com o seguinte código:

var meuDevice = localStorage.getItem("device")
alert("Device:" + meuDevice)

No código acima passamos a função getItem e como parâmetro passamos a key do dado que queremos resgatar, na linha seguinte apenas damos um alert para exibir a informação.

Caso queria remover essa informação do localStorage utilizamos o seguinte código:

localStorage.removeItem("device")

Agora vamos para um exemplo prático aplicando essas três funções que virmos acima, no caso: salvar, ler e excluir os dados no localStorage.

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<script>
		window.addEventListener("load",function(){
			
			if(localStorage.getItem("name")){
				sayMyName()
			}else{
				whatsYourName()
			}
		});
		
		function whatsYourName(){
			var campo = "<input type='text' id='nome' placeholder='Qual é o seu nome'/><button id='bt-save'>Salvar</button>";
			
			document.body.innerHTML = campo
			document.getElementById("bt-save").addEventListener("click",saveName)
		}
		
		
		function sayMyName(){
			var mensagem = "<h1> Olá " + localStorage.getItem("name") + "</h1><button id='bt-remove'>Remover</button>";
			
			document.body.innerHTML = mensagem;
			document.getElementById("bt-remove").addEventListener("click",removeName)
		}
		
		function removeName(){
			if(localStorage.getItem("name")){
				localStorage.removeItem("name");
				whatsYourName()
			}	
		}
		
		function saveName(){
			var nome = document.getElementById("nome").value;
			localStorage.setItem("name", nome) 
			sayMyName();
		}
	</script>
</head>
<body>
</body>
</html>

O Exemplo é bem simples ele verifica se tem o dado “name”, caso tenha, exibe o nome. Caso contrário adiciona um input para cadastrar o dado. Quando o nome é exibido também adicionamos um button para chamar a função de excluir os dados. Nos Exemplos anteriores apenas adicionamos e removemos algumas strings, para trabalhar com objetos no localStorage precisamos usar a Classe JSON, com ela é possível fazer a ponte entre texto e objetos.

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>save and load object</title>
	<script>
		
		
		window.addEventListener("load",function(){
			if(localStorage.getItem("user")){
				var texto = localStorage.getItem("user");
				var objeto = JSON.parse(texto);
				document.body.innerHTML = "nome: <strong>" + objeto.name + "</strong>" + 
				" email: <strong>" + objeto.email + "<strong>"
			}else{
				var user = { 
					name:"Fellyph",
					email:"fellyph@blackberry.com"
				}
			
				var userString = JSON.stringify(user);
	
				localStorage.setItem("user",userString);
				document.body.innerHTML = "dados salvos"	
			}
		})
	</script>
</head>
<body>
	
</body>
</html>

No código acima verificamos se existe um dado com uma key “user”, caso exista ele resgata a informação na variável “texto” em seguida converte o texto em objeto com a classe JSON através da função parse que passamos como parâmetro o nosso texto armazenado no localStorage, na sequência adicionamos o conteúdo no body do nosso arquivo. Caso o usuário não tenha nenhuma informação salva, o código irá criar um objeto “user” e em seguida “stringificar” o nosso objeto assim salvado os dados em nosso localStorage. Esse exemplo não é muito funcional apenas exemplifica como é salvar um objeto em nosso localStorage.

Agora vamos partir para um exemplo mais funcional, vamos montar uma todo-list utilizando localStorage, desta vez vamos separar o código no arquivo todo-list.html, js/app.js e css/style.css. Caso queira baixar o exemplo ele e os anteriores estão disponíveis no gitHub no seguinte link: https://github.com/fellyph/Tutorial-bbUI/tree/master/localstorage

Inicialmente nosso HTML:

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Todo List</title>
	<link rel="stylesheet" href="css/style.css">
	<script src="js/app.js"></script>
</head>
<body>
	<h1>todo-list</h1>
	<div id="tasks-output"></div>
	<form id="form-task">
		<input type="text" name="descricao" placeholder="adicione uma nova task" required>
		<input type="submit" value="Salvar">
	</form>
</body>
</html>

Nosso CSS:

#tasks-output li {
	cursor: pointer;
}

#form-task {
	border-top: 1px solid #ddd;
	padding: 10px 0;
	margin: 10px 0;
}

#tasks-output li[data-done="true"] {
	text-decoration: line-through;
}

Detalhe para o ultimo seletor que trata quando o item da lista possui o atributo data-done igual a true, ele vai adicionar uma linha sobre o texto.

Agora o nosso JS:

var todoList;
		var todoOutput;
		
		window.addEventListener("load",function(){
			//guarda em uma variável o elemento tasks-output
			todoOutput = document.getElementById("tasks-output")
			if(localStorage.getItem("tasks")){
				todoList = JSON.parse(localStorage.getItem("tasks"));
				showList()
			}else{
				todoList = [];
			}
			
			if(todoList.length == 0){
				todoOutput.innerHTML = "Nenhuma tarefa cadastrada"
			}
			//adiciona o listener para o evento submit, utilizei form para usar o required do input HTML
			document.getElementById("form-task").addEventListener("submit",onSubmit);
			todoOutput.addEventListener("click",clickList)
		})
		
		function clickList(e){
			//somente fazer algo quando clicar em um item li
			if(e.target.localName == "li"){
				e.target.dataset.done = (e.target.dataset.done === 'true')? false : true;
				todoList[e.target.dataset.id].done = e.target.dataset.done;
				saveList();
			}else if(e.target.localName == "button"){
				clearList()
			}
		}
		
		function onSubmit(e){
			var task = {};
		
			//pego o valor cadastrado no primeiro input do meu form
			task.descricao = e.target[0].value;
			task.date = new Date();
			task.id = todoList.length;
			task.done = "false";
			
			//adicionando a task na lista
			todoList.push(task);
			saveList();
			showList();
			// utiliza o preventDefault para evitar do form realizar o reload da página
			e.preventDefault();
		}
		
		function saveList(){
			//converte os dados em string e salva no local storage 
			localStorage.setItem("tasks",JSON.stringify(todoList));
		}
		
		function clearList(){
			//varre a lista a procura de tarefas realizadas
			for(var i = 0; i < todoList.length; i++){
				if(todoList[i].done === 'true'){
					todoList.splice(i, 1);  //remove 1 elemento na posição i;
					i = 0;  //voltando o indice no array para validar novamente a lista
				}else{
					todoList[i].id = i;
				}
			}
			showList();
			saveList();
		}
		
		function showList(){
			//mostra a lista de todo
			var total = todoList.length;
			if(total > 0){
				var htmlTemp = "<ul>"; 
				for(var i = 0; i < total; i++){
					htmlTemp += "<li data-id='"+todoList[i].id+"' data-done='" + todoList[i].done + "'>"+ todoList[i].descricao + " - "+ formatDate(todoList[i].date)+"</li>"
				}
				htmlTemp += "</ul><button>Limpar tarefas realizadas</button>";
				todoOutput.innerHTML = htmlTemp;
			}else{
				todoOutput.innerHTML = "Nenhuma tarefa cadastrada"
			}
		}
		
		function formatDate(date){
			// formata a data para o formato DD/MM/YYYY
			var time = new Date(date);
			var saida = time.getDate() +"/"+ time.getMonth() + "/" + time.getFullYear();
			return saida;
		}

Tentei comentar os pontos mais importantes do código, no exemplo acima o usuário pode cadastrar as tasks que serão vinculadas uma data, quando o usuário clica no item da lista a propriedade “data-done” muda entre true ou false. caso o usuário queira limpar sua listas de task clica no botão “Limpar tarefas…” o código irá varrer da lista os itens com valor da propriedade data-done igual a true e retirar da lista.

Além do LocalStorage temos o SessionStorage, a diferença entre os dois é que o sessionStorage como o nome sugere ele guarda as informações apenas na seção ou seja no caso de um app mobile, quando o app é finalizado a informação é removida.