lorenzo

Dec 122012
 

jQuery Mobile usa ajax come scelta preferienzale per caricare altri contenuti.

Usiamo come esempio questa semplice pagina:

<!DOCTYPE html>
<html>
<head>
<title>Linking AJAX</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css">
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>Linking AJAX</h1></div>
<div data-role="content">
<p><a href="04b-link.html">Link to an external file</a></p>
<p><a href="04b-link.html" data-prefetch>Prefetch the external file</a></p>
</div>
</div>
</body>
</html>

Come si può vedere esaminadno il codice sorgente della pagina caricata, che non porta con sé il caricamento agli script necessari e al css, effettivamente lo schema utilizzato è ajax, il secondo link procede anche a un precaricamento, tecnica utile per velocizzare la fruizione dei contenuti ma della quale è bene non abusare.

Il codice della 04b-link.html:

<!DOCTYPE html>
<html>
<head>
<title>Linked Page</title>
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>File linkato</h1></div>
<div data-role="content">
<p><a href="04-linking-ajax.html">Link al file originale</a></p>
</div>
</div>
</body>
</html>

Accedendo direttamente a questa pagina apparirà appunto completamente non formatta a riprova di quanto detto.

L’esempio

Dec 102012
 

jQuery Mobile normalmente utilizza ajax come tecnologia per il caricamento dei contenuti.

A questo bisogna ggiungere che una delle modalità caratteristiche di costruzione delle applicazioni e creare un unico file e inserire all’interno di questo diversi div con data-role=”page” che costituiscono le pagine vere e proprie del nostro sito.

Questa pagina, per esempio, usa ajax per passare dalla prima alla seconda pagine e viceversa: è la struttura di default di caricamento dei link.

<!DOCTYPE html>
 <html>
 <head>
 <title>Page Title</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css">
 <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
 <script type="text/javascript" src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
 </head>
 <body>

<div data-role="page" id="prima">
 <div data-role="header"><h1>Prima</h1></div>
 <div data-role="content">
 <a href="#seconda">Seconda</a>
 </div>
 </div>
 <div data-role="page" id="seconda">
 <div data-role="header"><h1>Seconda</h1></div>
 <div data-role="content">
 <a href="#prima">prima</a>
 </div>
 </div>
 </body>
 </html>

Questo pone un evidente problema sulla gestione dell’evento document.ready che si scatena una sola volta al caricamento della pagina completa.

L’evento che invece mi permette di intercettare il caricamento della singola pagina è “init”.

Modifichiamo i nostri due link in questo modo:

<a href="#seconda" data-role="button">Seconda</a>

...

<a href="#prima" data-role="button">prima</a>

e aggiungiamo uno script che tramite un alert segnala questa differenza:

<script>
 $(document).ready(function(e) {alert(0);});
 $(document).on('pageinit',function(){alert(1);});
 </script>

Al primo accesso alla prima pagina avremo due alert con contenuto 0 e 1,

all’accesso alla seconda pagina un solo alert con, ovviamente, 1.

L’esempio.

Dec 082012
 

Proviamo a costruire un feetto lightbox fatto in casa.

Ovviamente esistono molti plugin che fanno questo in modo estremamente evoluto, ma il nostro scopo è vedere un po’ cosa c’è dietro le quinte e magari avere una base per delle personalizzazioni.

Come risorse esterne serve solo jQuery e due immagini, un ajax loader per avvisare l’utente della richiesta e l’immagine naturalmente.

Nell’html mettiamo solo un contenitore on un link dove specifichiamo nell’href il path dell’immagine.


<div id=”contenitore”>
<a href=”images/mare.jpg”>pic</a>
</div>

Il css conterrà la formattazione per un overlay fra la pagine e l’immagine e l’id lightbox vero e proprio:


#overlay {position: fixed;top: 0;left: 0;height: 100%;width: 100%;background: black url(images/loader.gif) no-repeat scroll center center;}
#lightbox {position: fixed;}

Quindi prima cosa al caricamento bind del click sul nostro link:


$(‘a.lightbox’).click(function(e) {

Quindi nascondiamo la scrollbar:


$(‘body’).css(‘overflow-y’, ‘hidden’);

E poi appendiamo al body il div overlay, va appeso al top della pagina e animato in modo che da opacità 0, completamente opaco, arriva a semitrasparente:


$(‘<div id=”overlay”></div>’)
.css(‘top’, $(document).scrollTop())
.css(‘opacity’, ’0′)
.animate({‘opacity’: ’0.5′}, ‘slow’)
.appendTo(‘body’);

Appendiamo al body anche il div lightbox, ma nascosto:


$(‘<div id=”lightbox”></div>’)
.hide()
.appendTo(‘body’);

Creiamo l’immagine leggendo il src dall’href su cui c’è stato il click:


$(‘<img>’)
.attr(‘src’, $(this).attr(‘href’))

 

e la carichiamo:


.load(function() {
positionLightboxImage();
})

A caricamento avvenuto la posizioniamo con una funzione ad hoc al centro della pagina e la mostriamo con il adeIn(), era nascosta prima:


function positionLightboxImage() {
var top = ($(window).height() – $(‘#lightbox’).height()) / 2;
var left = ($(window).width() – $(‘#lightbox’).width()) / 2;
$(‘#lightbox’)
.css({
‘top’: top + $(document).scrollTop(),
‘left’: left
})
.fadeIn();
}

Al click sull’immagine al contrario la nascondiamo, o meglio, la rimuoviamo del tutto:


.click(function() {
removeLightbox();
})
function removeLightbox() {
$(‘#overlay, #lightbox’)
.fadeOut(‘slow’, function() {
$(this).remove();
$(‘body’).css(‘overflow-y’, ‘auto’); // show scrollbars!
});
}

Rirpistinando con questa funzione quindi lo stato iniziale della pagina:

Esempio

Dec 052012
 

Una cosa che potrebbe essere interessante è un sistema di navigazione frapagine basato su swipe, levento che siamo abituati a compiere sui nostri dispositivi touch.

Breve nota: si distingue dal tap perché è prolungato, come trascinaento, su almento 30px.

Potermmo usare questo sistemap er scorrere avanti le pagine, oppure indietro a seconda che lo swipe sia verso sinistra o verso destra.

Come prima cosa abbiamo bisogno di 3 padine, sempre all’interno dello stesso file dove avremo la solita intestazione:


<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<link rel=”stylesheet” href=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css” />
<script src=”http://code.jquery.com/jquery-1.8.2.min.js”></script>
<script src=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js”></script>

Le nostre 3 pagine, ovviamente banalissime, ciascuna con il suo id e tutte della classe .pagine


<div data-role=”page” id=”page1″>
<div data-role=”header”>
<h1>Page 1</h1>
</div>
<div data-role=”content”>
<p>Page 1</p>
</div>
</div>
<div data-role=”page” id=”page2″>
<div data-role=”header”>
<h1>Page 2</h1>
</div>
<div data-role=”content”>
<p>Page 2</p>
</div>
</div>
<div data-role=”page” id=”page3″>
<div data-role=”header”>
<h1>Page 3</h1>
</div>
<div data-role=”content”>
<p>Page 3</p>
</div>
</div>

Passiamo alla gestione degli eventi al $(document).ready(function()

prima cosa il bind, usando il metodo on dell’evento:


$(‘.pagine’).on(‘swipeleft’,function(event)

pertanto alla classe .pagine andiamo ad “attaccare” l’evento swipeleft

a questo punto dobbiamo sapere qul è la prossima pagina a partire  da quella corrente:



var nextpage = $(‘.ui-page-active’).next(‘.pagine’).attr(‘id’);

e ne ricaviamo l’id.

Ora possiamo spoastarci:


$.mobile.changePage(‘#’+nextpage, {    transition: “turn”})

aggiungendo anche un piccolo tocco con una transizione per segnalre che lo si può, ovviamente, fare.

Il movimento nell’altro verso è speculare:


$(‘.pagine’).on(‘swiperight’,function(event){
var prevpage = $(‘.ui-page-active’).prev(‘.pagine’).attr(‘id’);
$.mobile.changePage(‘#’+prevpage, {    transition: “turn”})
});

Per testare l’esempio occorre accedere alla pagina con un dispositivo touch.

Dec 022012
 

una seconda possibilità di gestire i form in jQuery Mobile è adottare delle soluzioni one page basandosi su ajax.

Per fare questo proveremo una pagina di lgoin con ritorno al form se la login fallisce oppure visualizzazione di un’altra pagina se la login va a buon fine.

Partiamo con le classiche intestazioni:


<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<link rel=”stylesheet” href=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css” />
<script src=”http://code.jquery.com/jquery-1.8.2.min.js”></script>
<script src=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js”></script>

In seguito creiamo la pagina di login con uno span dove eventualmente inserire il messaggio di errore:


<div data-role=”page” id=”login”>
<div data-role=”header”>
<h1>My Title</h1>
</div>
<span id=”error”></span>
<form id=”login_user” data-ajax=”false”>
<label>Email:</label>
<input type=”text” id=”email” name=”email”>
<label>Password:</label>
<input type=”text” id=”pwd” name=”pwd”>
<button type=”submit”>Submit</button>
</form>
</div>
</div>

Successivamente predisponiamo una semplicissima seconda pagina per il post login:


<div data-role=”page” id=”loginok”>
<div data-role=”header”>
<h1>My Title</h1>
</div>>
<div data-role=”content”>
<span id=”test”></span>
</div>
</div>

Passiamo alla sostanza, cioè al document.ready intercettiamo il submit del form e blocchiamo il comportamento di default:


$(document).ready(function(e) {
$(‘#login_user’).on(‘submit’, function (e) {
e.preventDefault();

In seconda battuta pre paro una variabile per il mio form e procedo con il post dei dati sulla form.php:


var $this = $(this);
$.post(
‘form.php’,
$this.serialize(),

I dati inseriti saranno passati con il metodo serialize().

La form.php è sostanzialmente “finta” ovvero è basata su un if anche se nella realtà verificherà le credenziali nel database.


<?php
$email=$_POST['email'];
$pwd=$_POST['pwd'];
if($email==’pippo@tin.it’ && $pwd==’pippo’){echo ‘ok’;}
else{echo ‘ko’;}
?>

Quindi se lo user è pippo@tin.it e la pwd pippo la login andrà a buon fine risponderà ok, viceversa la pagina risponderà ko

Andiamo a gestire la risposta:


function (str){
if(str==’ok’){
$(‘#test’).html(str);
$.mobile.changePage(‘#loginok’)
}
else{
$(‘#error’).html(‘Errore login’);
$.mobile.changePage(‘#login’)
}

Se la risposta è ok, l’utente visualizzerà la pagina in loginok, altrimenti inseriremo un messaggio nello span con id=error

e ritorneremo sulla logi.

L’esempio

Nov 292012
 

jQuery Mobile usa uno schema ajax per la gestione dei form, anche se il risultato finale può sembrare meno trasparente di quello che possiamo immaginare.
Partiamo con la costruzione della nostra pagina base, ci servirà un tema, jQuery e appunto jQuery Mobile:


<head>
<title>My Page</title>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<link rel=”stylesheet” href=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css” />
<script src=”http://code.jquery.com/jquery-1.8.2.min.js”></script>
<script src=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js”></script>
</head>

Poi costruiamo la classica pagina jqm riempiendo il content con un form per il login:


<div data-role=”page” id=”login”>
<div data-role=”header”>
<h1>My Title</h1>
</div><!– /header –>
<div data-role=”content”>
<span id=”error”></span>
<form id=”login_user” action=”form2.php” method=”post”>
<label>Email:</label>
<input type=”text” id=”email” name=”email”>
<label>Password:</label>
<input type=”text” id=”pwd” name=”pwd”>
<button type=”submit”>Submit</button>
</form>
</div><!– /content –>
</div><!– /page –>

Come di consueto il form viene spedito alla pagina indicata nella action con il metodo specificato,

jqm però invierà questa richiesta con l’oggetto XmlHttpRequest come si può osservare monitorando la apgina con firebug.

A questo punto possiamo supporre che la nostra pagina form2.php verifichi le credenziali e se la login non va a buon fine rimandi alla pagina di partenza, viceversa mostri il nuovo html.

Il controllo


<?php
$email=$_POST['email'];
$pwd=$_POST['pwd'];
if($email!=’pippo@tin.it’ || $pwd!=’pippo’){header(‘location: jqm_form2.html’);exit();}
?>

E la pagina html:


<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<link rel=”stylesheet” href=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css” />
<script src=”http://code.jquery.com/jquery-1.8.2.min.js”></script>
<script src=”http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js”></script>
<script>
</script>
</head>
<body>
<div data-role=”page” id=”loginok”>
<div data-role=”header”>
<h1>My Title</h1>
</div><!– /header –>
<div data-role=”content”>
<span id=”test”>ok</span>
</div><!– /content –>
</div><!– /page –>
</body>
</html>

L’esempio

Nov 262012
 

Uno dei problemi classici di google analytics è questo:
dato che si tratta di un codce javascript incorporato nella pagina, esso viene interpretato dal browser (a patto di non aver disabilitato il javascript appunto);
questo implicitamente vuol dire che in teoria non posso monitorare l’accesso a un file pdf, o a un file che non sia html.
La cosa sarebbe piuttosto limitante perché in diversi casi è proprio questo l’obiettivo pià interessante del monitoraggio.

Possiamo fare questo con la gestione degli eventi, che ci impone di personalizzare il codice js di google analytics ma poi consenitrà di monitarare nel pannel degli eventi tutto quanto.
Partiamo con il nostro codice per il monitoraggio del download di un pdf:

 <a onclick="_gaq.push(['_trackEvent', 'Download', 'Download Curriculum', 'Download Curriculum PDF']);" href="pdf/miopdf.pdf">curriculum</a>

Quindi all’evento on click verrà mandato al server di anlytics una chiamata di tipo _trackEvent,
a diffrenza delle pagine che sono _trackPages, dove passiam tre parametri:
categoria dell’evento, azione dell’evento, etichetta dell’evento.Questi parametri servono per avere la massima flessibilità nella lettura di quanto accade nelle nostre pagine.

Dal pannelo di analytics dedicato ai rapporti standard andiamo sulla scheda dei contenuti e alla voce eventi avremo tutte le informazioni registrate.

Nov 232012
 

Uno dei problemi concreti del css3 è fornire un adeguato supporto per i vecchi browser, al momento attuale si intende quindi internet explorer 7 e internet explorer 8.
Proviamo a usare la pseudo classe :after per aggiungere contenuti e useremo modernizr per testare il supporto, jquery entrerà in azione in caso di bisogno.
Procediamo dun que con l’html che conterrà semplicemente un paragrafo:


<p>Paragrafo di prova</p>

Con il css3 aggiungiamo un contenuto dopo il paragrafo, grazie alla pseudoclasse after, e lo formattiamo:

p:after{content:” – test”; background-color:yellow; color:red; font-weight:bold;}

Questa soluzione attualmente funziona con chrome, firefox, ie9, ma non con i vecchi ie.

Verificheremo allora il mancato supporto con modernizr,
costruiremo un download personalizzato con la sola opzione che ci interessa.
Aggiungeremo poi il js nell’intestazione della pagina:

e poi il solito jquery

A questo punto avviamo il test di supprto:

Andando a vedere con l’ispettore degli elementi l’html generato noteremo la classe generatedcontent assegnata al atg html qualora vi sia il supporto.
quindi modifichere il nostro css in questo modo:

.generatedcontent p:after{content:” – test”; background-color:yellow; color:red; font-weight:bold;}

I browser privi della classe generata da modernizr non cercheranno di applicare la formattazione.

Per loro ci sarà uno script ausiliario che richiameremo con il nope:

Modernizr.load({
test: Modernizr.generatedcontent,
nope: ‘js/generatedcontent.js’
});

ovvero se il test fallisce carica js/generatedcontent.js
che conterrà l’alternativa jQuery al nostro css:


$(‘p’).addClass(‘floatlf’).after(“ – test“);

Dove la classe floatlf è:

.floatlf{ float:left;}

e il css dello span:

span{ background-color:yellow; color:red; font-weight:bold;}

L’esempio finale

Nov 202012
 

jQuery nelle sue successive versioni ha cambiato più volte la modalità di associazione degli eventi agli oggetti html.
Il problema è particolarmente evidente quando dobbiamo assegnare un evento a un oggetto che viene aggiunto successivamente al caricamento alla nostra pagina, come, per esempio, nel caso di ajax.

All’inizio si usava il live, successivamente delegate, adesso on; i vecchi metodi sono supportati ma sconsigliati.

Proviamo quindi l’on, costruiremo una pagina con un bottone, al click creeremo un secondo bottone sul quale gestire a sua volta il click.
Partiamo dall’html:


<div id=”pulsanti”>
<input type=”button” id=”btn1″ value=”box1″>
</div>
<div id=”box1″></div>

Il css minimo:

.box{ width:300px; min-height:100px; border:1px solid #000; margin:10px;}

Al document.ready procediamo con la creazione del pulsante:

$(document).ready(function(e) {
$(‘#btn1′).click(function(){$(‘#pulsanti’).append(‘<input type=”button” id=”btn2″ value=”Append”>’);})
});

A questo punto si tratta di gestire l’evento click sul btn2 e useremo appunto on:

$(‘#pulsanti’).on(‘click’,'#btn2′,aggiungi)

con i parametri evento, selettore, callback, in questo caso si poteva anche usare una funzione anonima.

E se volessimo disablitare il click dopo l’esecuzione di un aggiungi? La risposta è intuitiva: off,
così gestiremo uno e un solo click sul btn2:


function aggiungi(){
$(‘#pulsanti’).off(‘click’,'#btn2′)
}

Esempio

Nov 172012
 

Oggi proviamo a usare il trigger. Che cos’è?
Beh diciamo un evento virtuale, o meglio nel nostro codice associamo un evento a un azione che l’utente dovrebbe compiere,
ma indeterminate circostanze scateneremo noi l’evento da programmazione.

Preparimao due bottoni e due div, semplicemente ciascun bottone nasconde un div.
L’html:


<input type=”button” id=”btn1″ value=”box1″>
<input type=”button” id=”btn2″ value=”box2″>
<div></div>
<div id=”box1″></div>
<div id=”box2″></div>

Il css:

.pulisci{ clear:left;}
.box{ width:100px; height:100px; float:left; margin:10px;}
#box1{ background-color:#F60;}
#box2{ background-color:#F6F;}

Il comportamento normale sarebbe questo:


$(document).ready(function(e) {
$(‘#btn1′).click(function(){$(‘#box1′).hide();})
$(‘#btn2′).click(function(){$(‘#box2′).hide();})
});

Bottone->click->nascondo div associato.

Ora supponiamo di voler far in modo che cliccando sul secondo div si nasconda anche il primo,
ovviamente potremmo lavorare sui selettori, ma seguiremo la via del trigger, così:


$(‘#btn2′).click(
function(){
$(‘#box2′).hide();
$(‘#btn1′).trigger(‘click’);
})

Cioè oltre a nascondere il box verrà scatenato un click sul btn1 che quindi nasconderà il primo box.

Esempio