iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur...

30
Applications iPhone avec HTML, CSS et JavaScript Conversion en natifs avec PhoneGap Jonathan Stark © Groupe Eyrolles, 2010, pour la présente édition, ISBN : 978-2-212-12745-4

Transcript of iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur...

Page 1: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

ApplicationsiPhone

avec HTML, CSS et JavaScript

Conversion en natifsavec PhoneGap

J o n a t h a n S t a r k

© Groupe Eyrolles, 2010, pour la présente édition, ISBN : 978-2-212-12745-4

Page 2: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

Table des matières

Avant-propos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 1

CHAPITRE 1

Démarrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 5

Applications web et applications natives� . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 5

Qu’est-ce�qu’une�application�web ?� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 5

Qu’est-ce�qu’une�application�native ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 6

Avantages�et�inconvénients�� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 6

Quelle�approche�vous�convient ?� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 7

Cours accéléré de programmation web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 7

Introduction�à�HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 7

Introduction�aux�CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 10

Introduction�à�JavaScript� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 13

CHAPITRE 2

Mise en forme iPhone simple� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 17

Premiers pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 18

Préparer�une�feuille�de�styles�distincte�pour�l’iPhone� . . . . . . . . . . . . . . . . . . . � 21

Contrôler�la�mise�à�l’échelle�de�la�page� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 22

Ajouter les styles CSS pour l’iPhone� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 23

Créer le look iPhone� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 26

Une touche d’interactivité avec jQuery� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 28

Ce que vous avez appris� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 34

Stark Livre.indb 5 30/04/10 14:40

Page 3: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

VIApplications iPhone avec HTML, CSS et Javascript

CHAPITRE 3

Mise en forme iPhone avancée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 35

Avec une pincée d’Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 35

Agent de la circulation� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 36

Petits gadgets simples� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 40

Développer votre propre bouton de retour� . . . . . . . . . . . . . . . . . . . . . . . . . . � 47

Ajouter une icône à l’écran d’accueil� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 54

Mode plein écran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 56

Changer�la�barre�d’état�� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 57

Fournir�une�image�de�démarrage�personnalisée� . . . . . . . . . . . . . . . . . . . . . . . � 58

Ce que vous avez appris� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 58

CHAPITRE 4

Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 61

Une aide précieuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 61

Glissements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 62

Ajouter le panneau Dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 66

Ajouter le panneau Date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 67

Ajouter le panneau Nouvelle entrée� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 70

Ajouter le panneau Réglages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 73

Assembler le tout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 75

Personnaliser jQTouch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 77

Ce que vous avez appris� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 80

CHAPITRE 5

Stockage de données côté client� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 81

localStorage et sessionStorage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 81

Enregistrer�des�réglages�utilisateur�dans�localStorage . . . . . . . . . . . . . . . . . . . � 83

Enregistrer�la�date�sélectionnée�dans�sessionStorage . . . . . . . . . . . . . . . . . . . . � 85

Base de données côté client� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 88

Créer�une�base�de�données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 89

Stark Livre.indb 6 30/04/10 14:40

Page 4: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

VII Table des matières

Insérer�des�lignes� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 93

Sélectionner�des�lignes�et�gérer�des�jeux�de�résultats . . . . . . . . . . . . . . . . . . . . � 96

Supprimer�des�lignes� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 100

Ce que vous avez appris� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 104

CHAPITRE 6

Passer en mode hors connexion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 105

Le cache d’application hors connexion� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 105

Liste blanche et options de remplacement . . . . . . . . . . . . . . . . . . . . . . . . . . . � 108

Créer un fichier de manifeste dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . � 112

Débogage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 117

La�console�JavaScript�� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 118

La�base�de�données�du�cache�d’application� . . . . . . . . . . . . . . . . . . . . . . . . . . . � 121

Ce que vous avez appris� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 128

CHAPITRE 7

Passer en version native . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 129

Introduction à PhoneGap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 129

Utiliser�la�hauteur�entière�de�l’écran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 135

Personnaliser�le�titre�et�l’icône . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 137

Créer�un�écran�de�démarrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 145

Installer votre application sur l’iPhone� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� .� . � 148

Contrôler l’iPhone en JavaScript� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 153

Bips,�vibrations�et�alertes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 153

Géolocalisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 157

Accéléromètre� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 163

Ce que vous avez appris� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 167

CHAPITRE 8

Envoyer votre application à iTunes� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 169

Créer un profil d’approvisionnement iPhone de distribution� . . . . . . . . . . � 170

Installer le profil d’approvisionnement iPhone de distribution . . . . . . . . . � 171

Renommer le projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 173

Stark Livre.indb 7 30/04/10 14:40

Page 5: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

VIIIApplications iPhone avec HTML, CSS et Javascript

Préparer le binaire de l’application� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 175

Envoyer votre application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 176

Pendant l’attente� . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 177

Autres ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 177

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . � 179

Stark Livre.indb 8 30/04/10 14:40

Page 6: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

3Mise en forme iPhone avancée

Afin�de�construire�notre�application�iPhone�sans�Objective-C,�nous�venons�de�voir�comment�uti-liser�des�CSS�pour�mettre�en�forme�une�série�de�pages�HTML�et�leur�donner�l’apparence�d’une�application�iPhone .�Dans�ce�chapitre,�nous�allons�réaliser�le�travail�de�fond�qui�permettra�à�ces�mêmes�pages�de�se�comporter comme�une�application�iPhone .�En�particulier,�nous�verrons�com-ment�utiliser�Ajax�pour�transformer�un�site�web�complet�en�une�application�monopage,�comment�créer�un�bouton�Précédent�avec�un�historique�en�JavaScript�et�comment�tirer�parti�des�fonction-nalités�des�icônes�de�clips�web�et�du�mode�plein�écran�de�l’iPhone,�pour�lancer�l’application�sans�que�Mobile�Safari�n’interfère�au�niveau�de�l’interface .

Avec une pincée d’AjaxLe�terme�Ajax�est�devenu�si�populaire�que�je�ne�suis�même�plus�sûr�de�savoir�encore�ce�qu’il�veut�dire .�Dans�ce�livre,�je�l’utiliserai�pour�faire�référence�à�la�technique�qui�consiste�à�utiliser�du�JavaScript�pour�transmettre�des�requêtes�à�un�serveur�web�sans�recharger�la�page�active�(par�exemple,�pour�récupérer�du�HTML,�poster�un�formulaire,�etc .) .�Cette�approche�rend�l’applica-tion�très�fluide�du�point�de�vue�de�l’utilisateur,�mais�elle�requiert�un�certain�nombre�d’efforts,�puisqu’elle�oblige�en�quelque�sorte�à�réinventer�la�roue .

Si�vous�chargez�dynamiquement�des�pages�externes,� le�navigateur�n’offre�aucune�indication�concernant�l’avancement�du�processus�ou�l’apparition�d’éventuelles�erreurs�aux�utilisateurs .�En�outre,�le�bouton�Précédent�ne�fonctionne�pas�comme�on�s’y�attendrait,�à�moins�que�vous�ne�fas-siez�l’effort�de�le�programmer�vous-même .�Il�faut�donc�se�remonter�les�manches�pour�créer�une�bonne�application�Ajax .�On�peut�toutefois�avoir�de�très�bonnes�raisons�de�faire�ces�efforts .�En�particulier,�il�devient�ainsi�possible�de�créer�des�applications�iPhone�qui�peuvent�s’exécuter�en�mode�plein�écran�(voir�la�section�Mode�plein�écran)�et�même�hors�connexion�(voir�chapitre 6) .

Stark Livre.indb 35 30/04/10 14:40

Page 7: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

36Applications iPhone avec HTML, CSS et Javascript

Agent de la circulationPour�la�prochaine�série�d’exemples,�nous�allons�créer�une�page�unique�appelée�iphone.html�qui�se�postera�au�devant�de�toutes�les�autres�pages�du�site�et�gérera�les�requêtes,�à�la�manière�d’un�agent�de�la�circulation .�Le�principe�de�fonctionnement�est�le�suivant :�au�premier�chargement,�iphone.html�présente�à�l’utilisateur�une�version�soigneusement�mise�en�forme�de�la�navigation�du�site .�Ensuite,�nous�utilisons�jQuery�pour�dérouter�les�actions�onclick�sur�les�liens�nav,�de�manière�que�lorsque�l’utilisateur�clique�sur�l’un�d’entre�eux,�le�navigateur�n’accède�pas�au�lien�cible .�Au�lieu�de�cela,�jQuery�charge�une�portion�du�code�HTML�de�la�page�distante�et�transmet�les�données�à�l’utilisateur�en�mettant�à�jour�la�page�actuelle .�Je�commencerai�par�la�version�fonc-tionnelle�la�plus�simple�du�code,�que�j’améliorerai�ensuite�progressivement .

Le�code�HTML�de�la�page�interface�iphone.html�est�extrêmement�simple�(voir�exemple 3-1) .�Dans�la�section�head,�je�définis�les�options�title�et�viewport�et�j’inclus�les�liens�vers�une�feuille�de�styles�(iphone.css)�et�deux�fichiers�JavaScript :�jquery.js�et�un�fichier�JavaScript�personnel�nommé�iphone.js .

InfoPour plus d’informations sur l’endroit où récupérer le fichier jquery.js et pour savoir quoi faire avec, consultez la section « Introduction à JavaScript » du chapitre 1.

La�section�body�contient�deux�div�conteneurs :�une�div�header�dont�le�titre�initial�se�trouve�dans�une�balise�h1�et�un�div�vide�container,�qui�contiendra�les�fragments�de�HTML�récupérés�dans�d’autres�pages .

Exemple 3-1. Ce code HTML simple de structure se placera au devant de toutes les autres pages du site

<html><head> <title>Jonathan Stark</title> <meta name="viewport" content="user-scalable=no, width=device-width" /> <link rel="stylesheet" href="iphone.css" type="text/css" media="screen" /> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="iphone.js"></script></head><body> <div id="header"><h1>Jonathan Stark</h1></div> <div id="container"></div></body></html>

Passons�à�iphone.css .�Comme�le�montre�l’exemple 3-2,�j’ai�réorganisé�certaines�propriétés�des�précédents�exemples�(certaines�des�propriétés�#header h1�ont�été�remontées�vers�#header) .�Dans�l’ensemble,�tout�devrait�cependant�vous�être�familier�(sinon,�relisez�le�chapitre 2) .

Stark Livre.indb 36 30/04/10 14:40

Page 8: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

37 Mise en forme iPhone avancée

Chapitre3

Exemple 3-2. Les styles CSS de base de la page ne sont qu’une version réorganisée des exemples précédents

body { background-color: #ddd; color: #222; font-family: Helvetica; font-size: 14px; margin: 0; padding: 0;}#header { background-color: #ccc; background-image: -webkit-gradient(linear, left top, left bottom, from(#ccc), ➥ to(#999)); border-color: #666; border-style: solid; border-width: 0 0 1px 0;}#header h1 { color: #222; font-size: 20px; font-weight: bold; margin: 0 auto; padding: 10px 0; text-align: center; text-shadow: 0px 1px 0px #fff;}ul { list-style: none; margin: 10px; padding: 0;}ul li a { background-color: #FFF; border: 1px solid #999; color: #222; display: block; font-size: 17px; font-weight: bold; margin-bottom: -1px; padding: 12px 10px; text-decoration: none;}ul li:first-child a { -webkit-border-top-left-radius: 8px; -webkit-border-top-right-radius: 8px;}ul li:last-child a { -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px;

Stark Livre.indb 37 30/04/10 14:40

Page 9: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

38Applications iPhone avec HTML, CSS et Javascript

}ul li a:active,ul li a:hover { background-color:blue; color:white;}#content { padding: 10px; text-shadow: 0px 1px 0px #fff;}#content a { color: blue;}

Le�code�JavaScript�dans�iphone.js�est�l’antre�où�sont�réalisées�toutes�les�opérations�de�magie�de�cet�exemple .�Référez-vous�à�l’exemple 3-3�pendant�que�je�le�parcours�ligne�par�ligne .

InfoCe code JavaScript charge un document appelé index.html sans lequel il ne peut fonctionner. Vous devez réutiliser le fichier HTML du chapitre 2, en vous assurant de l’enregistrer sous le nom index.html dans le même répertoire que le fichier iphone.html que vous avez créé précédemment dans ce chapitre. Toutefois, aucun des liens qui y figurent ne pourra fonctionner si les cibles des liens n’existent pas. Vous pouvez créer ces fichiers vous-même ou télécharger le code d’exemple du site web du livre. En créant about.html, blog.html et consulting-clinic.html, vous dispose-rez de quelques liens avec lesquels vous amuser. Pour cela, contentez-vous de dupliquer index.html plusieurs fois et changez le nom de fichier de chaque copie pour le faire correspondre au lien qui s’y rapporte. Pour plus d’effet, vous pouvez modifier le contenu de la balise h2 dans chaque fichier pour le faire correspondre au nom du fichier. Par exemple, l’élément h2 de blog.html peut être <h2>Blog</h2>.

Exemple 3-3. Ce fragment de JavaScript dans iphone.js convertit les liens de la page en requêtes Ajax

$(document).ready(function(){ loadPage();});function loadPage(url) { if (url == undefined) { $('#container').load('index.html #header ul', hijackLinks); } else { $('#container').load(url + ' #content', hijackLinks); }}function hijackLinks() { $('#container a').click(function(e){ e.preventDefault(); loadPage(e.target.href); });}

Stark Livre.indb 38 30/04/10 14:40

Page 10: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

39 Mise en forme iPhone avancée

Chapitre3

�Ici,�j’utilise�la�fonction�$(document).ready()�de�jQuery�pour�amener�le�navigateur�à�exécuter�la�fonction�loadPage()�lorsque�le�DOM�est�complètement�chargé .

�La�fonction�loadPage()�prend�un�unique�paramètre�appelé�url,�puis�vérifie�(à�la�ligne�sui-vante)�si�une�valeur�a�été�envoyée .

�Si�aucune�valeur�n’est�envoyée�dans�la�fonction,�url�est� indéfinie�et�cette�ligne�s’exécute .�Cette�ligne�et�la�suivante�sont�des�exemples�de�la�fonction�load()�de�jQuery .�Cette�fonction�est�parfaite�pour�ajouter�des�fonctionnalités�Ajax�simples�et�rapides�à�une�page .�En�français,�on�pourrait�traduire�cette�ligne�ainsi :�« Récupérer�tous�les�éléments�ul�de�l’élément�#header�d’index.hml�et� les�insérer�dans�l’élément�#container�de�la�page�actuelle .�Enfin,�exécuter�la�fonction�hijackLinks() » .�Notez�qu’index.html�fait�référence�à�la�page�d’accueil�du�site .�Si�votre�page�d’accueil�porte�un�nom�différent,�utilisez-le�à�la�place .

�Cette�ligne�est�exécutée�si�le�paramètre�url�possède�une�valeur .�Elle�dit�en�somme :�« Récu-pérer�l’élément�#content�de�l’url�qui�a�été�passée�à�la�fonction�loadPagest()�et�l’insérer�dans�l’élément�#content�de�la�page�actuelle .�Enfin,�exécuter�la�fonction�hijackLinks() » .

�Une�fois�que�la�fonction�load()�a�terminé,�l’élément�#container�de�la�page�actuelle�contient�le�fragment�HTML�récupéré .�Ensuite,�load()�exécute�la�fonction�hijackLinks() .

�Dans�cette�ligne,�hijackLinks()� trouve�tous�les�liens�dans�le�nouveau�code�HTML�et�leur�associe�un�gestionnaire�de�clic�avec�les�lignes�de�code�qui�suivent .�Les�gestionnaires�de�clic�se�voient�passer�de�manière�automatique�un�objet�événement,�que�je�capture�sous�la�forme�d’un�paramètre�de�fonction�e .�L’objet�événement�d’un�lien�cliqué�contient�l’URL�de�la�page�distante�dans�e.target.href .

�Normalement,�le�navigateur�web�se�rend�sur�la�nouvelle�page�quand�l’utilisateur�clique�sur�un�lien .�C’est�ce�qu’on�peut�appeler�le�« comportement�par�défaut »�du�lien .�Ici,�comme�nous�gérons�manuellement�les�clics�et�le�chargement�des�pages,�nous�devons�bloquer�ce�compor-tement .�C’est�ce�que�fait�cette�ligne,�en�appelant�la�méthode�prédéfinie�preventDefault()�de�l’objet�événement .�Si�je�l’avais�omise,�le�navigateur�aurait�accompli�son�devoir�en�quittant�la�page�actuelle�et�en�accédant�à�l’URL�du�lien�cliqué .

�Lorsque�l’utilisateur�clique,�nous�passons�l’URL�de�la�page�distante�à�la�fonction�loadPage()�et�le�cycle�recommence .

InfoL’une des caractéristiques les plus intéressantes du JavaScript tient à la possibilité qui vous est offerte de passer une fonction en paramètre à une autre fonction. Cela peut paraître étrange au premier abord, mais c’est en vérité très utile pour créer du code modulaire et réutilisable.

Les�gestionnaires�de�clic�ne�s’exécutent�pas�quand�la�page�se�charge�au�départ .�Ils�le�font�lorsque�l’utilisateur�a�lu�une�partie�de�la�page�et�décide�de�cliquer�sur�un�lien .�Cette�manière�d’attribuer�les�gestionnaires�de�clic�s’apparente�à�la�pose�de�pièges ;�vous�devez�réaliser�un�travail�de�prépa-ration�initial�pour�quelque�chose�qui�peut�être,�ou�pas,�déclenché�par�la�suite .

Stark Livre.indb 39 30/04/10 14:40

Page 11: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

40Applications iPhone avec HTML, CSS et Javascript

InfoIl peut être utile de prendre quelques minutes pour lire les propriétés de l’objet événement que le JavaScript crée en réponse aux actions de l’utilisateur dans le navigateur. Vous trouverez des informations de références à l’adresse http://www.w3schools.com/htmldom/dom_obj_event.asp.

Petits gadgets simplesAvec�ces�petits�bouts�de�HTML,�de�CSS�et�de�JavaScript,�nous�avons�transformé�un�site�web�complet�en�une�application�monopage .�Il�reste�cependant�beaucoup�à�faire .�Tâchons�de�peaufi-ner�cette�première�ébauche .

Comme�nous�ne�permettons�pas�au�navigateur�d’aller�de�page�en�page,� l’utilisateur�ne�voit�aucune�indication�de�l’état�d’avancement�pendant�que�les�données�se�chargent .�Il�faut�un�moyen�de�lui�faire�savoir�qu’il�se�passe�quelque�chose .�Sans�cela,�il�se�demandera�s’il�a�bien�cliqué�sur�le�lien�ou�s’il�l’a�manqué,�et�se�mettra�certainement�à�cliquer�à�tout�va�en�se�frustrant .�La�charge�serveur�peut�être�alourdie�et�l’application�devenir�instable�(crasher) .

InfoSi vous testez cette application web sur un réseau local, les vitesses réseau seront si rapides que vous ne verrez pas l’indicateur de progression. Si vous utilisez Mac OS X, vous pouvez ralentir tout le trafic web entrant en tapant deux commandes ipfw dans le terminal. Par exemple, les com-mandes suivantes ralentissent tout le trafic web à 4 kilooctets par seconde :

sudo ipfw pipe 1 config bw 4KByte/ssudo ipfw add 100 pipe 1 tcp from any to me 80

Si vous employez le navigateur Safari de bureau pour observer les pages, vous devez utiliser le nom d’hôte de votre Mac ou une adresse IP externe dans l’URL (par exemple, monmac.local plutôt que localhost). Lorsque vous avez fini vos tests, supprimez la règle avec sudo ipfw delete 100 (vous pouvez supprimer toutes les règles personnalisées avec ipfw flush).

Grâce�à�jQuery,�il�suffit�de�deux�lignes�de�code�pour�livrer�ce�genre�d’information .�Nous�allons�donc�simplement�ajouter�une�div�de�chargement�à�l’élément�body� lorsque�loadPage()�démarre,�puis�supprimer�la�div�de�chargement�lorsque�hijackLinks()�a�terminé .�L’exemple 3-4�présente�une�version�modifiée�de�l’exemple 3-3 .�Les�lignes�que�vous�devez�ajouter�à�iphone.js�sont�affi-chées�en�gras .

Exemple 3-4. Ajout d’un indicateur de progression à la page

$(document).ready(function(){ loadPage();});function loadPage(url) { $('body').append('<div id="progress">Loading...</div>');

Stark Livre.indb 40 30/04/10 14:40

Page 12: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

41 Mise en forme iPhone avancée

Chapitre3

if (url == undefined) { $('#container').load('index.html #header ul', hijackLinks); } else { $('#container').load(url + ' #content', hijackLinks); }}function hijackLinks() { $('#container a').click(function(e){ e.preventDefault(); loadPage(e.target.href); }); $('#progress').remove(); }

L’exemple 3-5�indique�les�instructions�CSS�qui�doivent�être�ajoutées�à�iphone.css�pour�mettre�en�forme�la�div�de�progression .�Le�résultat�est�présenté�figure 3-1 .

Figure 3-1

Sans indicateur de progression, votre application paraîtra manquer de réactivité et vos utilisateurs se sentiront frustrés.

Stark Livre.indb 41 30/04/10 14:40

Page 13: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

42Applications iPhone avec HTML, CSS et Javascript

Exemple 3-5. Règles CSS ajoutées à iphone.css pour mettre en forme l’indicateur de progression

#progress { -webkit-border-radius: 10px; background-color: rgba(0,0,0,.7); color: white; font-size: 18px; font-weight: bold; height: 80px; left: 60px; line-height: 80px; margin: 0 auto; position: absolute; text-align: center; top: 120px; width: 200px;}

Chaque�page�de�mon�site�possède�un�unique�titre�h2�tout�en�haut,�qui�conviendrait�bien�comme�titre�de�page�(voir�figure 3-2) .�Vous�le�remarquerez�dans�le�code�HTML�source�présenté�au�chapitre 2 .

Figure 3-2

Avant que le titre de la page ne soit reporté dans la barre d’outils…

Stark Livre.indb 42 30/04/10 14:40

Page 14: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

43 Mise en forme iPhone avancée

Chapitre3

Pour�donner�à�ce�titre�un�aspect�plus�propre�à�l’iPhone,�je�vais�l’extraire�du�contenu�et�le�placer�dans�l’en-tête�(voir�figure 3-3) .�Cette�fois�encore,�c’est�jQuery�qui�va�m’y�aider :�il�suffit�d’ajouter�trois�lignes�à�la�fonction�hijackLinks()�pour�que�le�miracle�se�produise .�L’exemple 3-6�présente�la�fonction�hijackLinks�avec�ces�changements .

Figure 3-3

Après que le titre de la page a été reporté dans la barre d’outils…

Exemple 3-6. Utilisation du titre h2 de la page cible comme titre de la barre d’outils

function hijackLinks() { $('#container a').click(function(e){ e.preventDefault(); loadPage(e.target.href); }); var title = $('h2').html() || 'Hello!'; $('h1').html(title); $('h2').remove(); $('#progress').remove();}

Stark Livre.indb 43 30/04/10 14:40

Page 15: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

44Applications iPhone avec HTML, CSS et Javascript

InfoNotez que j’ai ajouté les lignes avant celle qui supprime l’indicateur de progression. Je préfère ôter l’indicateur de progression à la toute dernière étape, car l’application paraît ainsi plus réactive.

La�double�barre�verticale�(||)�dans�la�première�ligne�du�code�inséré�(signalé�en�gras)�correspond�à�l’opérateur�logique�OR�en�JavaScript .�En�français,�cette�ligne�se�traduirait�ainsi :�« attribuer�à�la�variable�de�titre�le�contenu�HTML�de�l’élément�h2�ou�la�chaîne�“Hello !”�à�défaut » .�C’est�important,�car�la�première�page�ne�contient�pas�de�h2,�puisque�nous�ne�faisons�que�récupérer�les�ul�de�navigation .

InfoCe point mérite quelque explication. Lorsque les utilisateurs chargent au départ l’URL iphone.html, ils ne voient que les éléments de la navigation générale du site et non le contenu du site lui-même. Celui-ci n’apparaît qu’après qu’ils ont appuyé sur un lien dans la page de navigation initiale.

Figure 3-4

Le texte qui revient à la ligne dans la barre d’outils ne fait pas très « iPhone »…

Stark Livre.indb 44 30/04/10 14:40

Page 16: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

45 Mise en forme iPhone avancée

Chapitre3

Certaines�pages�du�site�possèdent�des�titres�trop�longs�pour�tenir�dans�la�barre�d’en-tête�(voir�figure 3-4) .�Je�pourrais�laisser�le�texte�revenir�à�la�ligne,�mais�cela�ne�fait�pas�trop�« iPhone » .�À la�place,� j’ai�donc�mis�à�jour�les�styles�#header h1�de�manière�que�le�texte�long�soit� tron-qué�avec�trois�points�de�suspension�(voir�figure 3-5�et�exemple 3-7) .�Parmi�les�astuces�CSS��méconnues,�il�s’agit�de�l’une�de�mes�favorites .

Figure 3-5

…mais on peut l’embellir avec des points de suspension en CSS.

Exemple 3-7. Ajout de trois points de suspension au texte trop long pour son conteneur

#header h1 { color: #222; font-size: 20px; font-weight: bold; margin: 0 auto; padding: 10px 0; text-align: center; text-shadow: 0px 1px 0px #fff; max-width: 160px; overflow: hidden; white-space: nowrap;

Stark Livre.indb 45 30/04/10 14:40

Page 17: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

46Applications iPhone avec HTML, CSS et Javascript

text-overflow: ellipsis;}

La�synthèse�est�simple :�max-width: 160px�demande�au�navigateur�de�ne�pas�permettre�à�l’élé-ment�h1�de�s’étendre�au-delà�de�160�pixels .�Ensuite,�overflow: hidden�demande�au�navigateur�de�tronquer�tout�le�contenu�qui�s’étend�en�dehors�des�bordures�de�l’élément .�white-space: nowrap�empêche�alors�le�navigateur�de�décomposer�la�ligne�en�deux .�Sans�cette�ligne,�le�titre�h1�s’éti-rerait�simplement�en�hauteur�pour�adapter�le�texte�à�la�largeur�définie .�Pour�finir,�text-overflow: ellipsis�ajoute�trois�points�de�suspension�à�la�fin�de�tout�texte�tronqué�afin�d’indiquer�aux�utili-sateurs�qu’ils�ne�voient�pas�la�chaîne�entière .

Considérez�le�cas�d’une�page�À�propos�qui�serait�plus�longue�que�la�zone�visible�sur�l’iPhone .�L’utilisateur�consulte�cette�page,�la�fait�défiler�vers�le�bas�pour�la�lire�et�clique�ensuite�sur�un�lien�vers�votre�page�Contact .�Si�la�page�Contact�contient�un�texte�très�long,�les�nouvelles�données�apparaîtront�mais�la�fenêtre�restera�calée�en�bas�comme�si�l’utilisateur�l’avait�fait�défiler .

Techniquement,�c’est�assez�logique,�car�nous�ne�quittons�pas�notre�page�actuelle�(que�l’utili-sateur�a�fait�défiler),�mais�pour�l’utilisateur,�c’est�forcément�déroutant .�Pour�corriger�cela,�j’ai�ajouté�une�commande�scrollTo()�à�la�fonction�loadPage()�(voir�l’exemple 3-8) .

Maintenant,�à�chaque�fois�qu’un�utilisateur�clique�sur�un�lien,�il�revient�en�haut�de�la�page .�Ce�mécanisme�a�également�l’avantage�d’assurer�que�l’image�qui�se�charge�est�visible�si�l’utilisateur�clique�sur�un�lien�en�bas�d’une�longue�page .

Exemple 3-8. Il est judicieux de revenir en haut de la page lorsqu’un utilisateur navigue vers une nouvelle page

function loadPage(url) { $('body').append('<div id="progress">Loading...</div>'); scrollTo(0,0); if (url == undefined) { $('#container').load('index.html #header ul', hijackLinks); } else { $('#container').load(url + ' #content', hijackLinks); }}

Comme�la�plupart�des�sites,�le�mien�possède�des�liens�vers�des�pages�externes�(hébergées�sur�d’autres�domaines) .

Je�ne�souhaite�pas�détourner�ces� liens,�parce�qu’il�ne�serait�pas� logique�d’injecter� leur�code�HTML�à�l’intérieur�de�ma�mise�en�page�spécifique�à�l’iPhone .�Dans�l’exemple 3-9,�j’ai�ajouté�une�instruction�conditionnelle�qui�vérifie�que�mon�nom�de�domaine�figure�dans�l’URL .�S’il�s’y�trouve,�le�lien�est�piraté�et�le�contenu�chargé�directement�dans�la�page�courante ;�Ajax�fait�son�œuvre .�Sinon,�le�navigateur�conduit�normalement�à�l’URL�de�destination .

InfoVous devez remplacer jonathanstark.com par le nom de domaine ou d’hébergement approprié pour votre site web, sans quoi les liens vers les pages de votre site ne seront pas détournées.

Stark Livre.indb 46 30/04/10 14:40

Page 18: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

47 Mise en forme iPhone avancée

Chapitre3

Exemple 3-9. Vous pouvez permettre aux pages externes de se charger normalement en vérifiant le nom de domaine de l’URL

function hijackLinks() { $('#container a').click(function(e){ var url = e.target.href; if (url.match(/jonathanstark.com/)) { e.preventDefault(); loadPage(url); } }); var title = $('h2').html() || 'Hello!'; $('h1').html(title); $('h2').remove(); $('#progress').remove();}

InfoLa fonction url.match utilise un langage appelé « expressions régulières », qui est souvent incorporé dans les autres langages de programmation comme JavaScript, PHP ou Perl. Cette expression régulière est simple, mais d’autres, plus complexes, peuvent être intimidantes ; il vaut cependant la peine de vous y accoutumer. Ma page favorite sur le sujet se trouve à l’adresse http://www.regular-expressions.info/javascriptexample.html.

Développer votre propre bouton de retourLe�gros�hic,�en�l’état�actuel�des�choses,�est�que�l’utilisateur�ne�dispose�d’aucun�moyen�de�navi-guer�vers�les�pages�précédentes�(rappelez-vous�que�nous�avons�détourné�tous�les�liens,�si�bien�que�l’historique�des�pages�de�Safari�ne�fonctionne�plus) .�Pour�résoudre�ce�problème,�ajoutez�un�bouton�de�retour�(une�sorte�de�bouton�Précédent)�en�haut�à�gauche�de�l’écran .�Pour�commencer,�nous�allons�mettre�à�jour�le�code�JavaScript,�puis�nous�occuper�des�CSS .

Pour�ajouter�un�bouton�de�retour�standard�de�style�iPhone�à�l’application,�il�faut�tenir�un�registre�de�l’historique�des�clics�de�l’utilisateur .�Pour�cela,�nous�devons�d’abord�stocker�l’URL�de�la�page�précédente�afin�de�savoir�où�revenir,�et�ensuite�stocker�le�titre�de�la�page�précédente�afin�de�savoir�quel�intitulé�donner�au�bouton�de�retour .

L’ajout�de�cette�fonctionnalité�affecte�la�plupart�du�code�JavaScript�que�nous�avons�écrit�jusque-là,�dans�ce�chapitre ;�je�vais�donc�commenter�la�nouvelle�version�d’iphone.js�ligne�par�ligne�(voir�l’exemple 3-10) .�Le�résultat�ressemblera�à�celui�de�la�figure 3-6 .

Stark Livre.indb 47 30/04/10 14:40

Page 19: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

48Applications iPhone avec HTML, CSS et Javascript

Figure 3-6

Pourrait-on vraiment parler d’application iPhone sans ce beau bouton luisant, en forme de flèche qui pointe vers la gauche ?

Exemple 3-10. Exemple JavaScript existant, étendu pour la prise en charge du bouton de retour

var hist = []; var startUrl = 'index.html'; $(document).ready(function(){ loadPage(startUrl);});function loadPage(url) { $('body').append('<div id="progress">Loading...</div>'); scrollTo(0,0); if (url == startUrl) { var element = ' #header ul'; } else { var element = ' #content'; } $('#container').load(url + element, function(){ var title = $('h2').html() || 'Hello!'; $('h1').html(title); $('h2').remove();

Stark Livre.indb 48 30/04/10 14:40

Page 20: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

49 Mise en forme iPhone avancée

Chapitre3

$('.leftButton').remove(); hist.unshift({'url':url, 'title':title}); if (hist.length > 1) { $('#header').append('<div class="leftButton">'+hist[1].title+'</div>'); $('#header .leftButton').click(function(){ var thisPage = hist.shift(); var previousPage = hist.shift(); loadPage(previousPage.url); }); } $('#container a').click(function(e){ var url = e.target.href; if (url.match(/jonathanstark.com/)) { e.preventDefault(); loadPage(url); } }); $('#progress').remove(); });}

�Dans�cette�ligne,�j’initialise�une�variable�nommée�hist�sous�forme�de�tableau�vide .�Comme�je�l’ai�définie�en�dehors�de�toute�fonction,�elle�possède�une�portée�globale�et�sera�disponible�partout�dans�la�page .�Notez�que�je�n’ai�pas�utilisé�le�mot�complet�history�comme�nom�de�variable,�car�il�s’agit�d’une�propriété�d’objet�en�JavaScript,�qui�doit�donc�être�évitée�dans�votre�propre�code .

�Ici,�je�définis�l’URL�relative�de�la�page�distante�à�charger�lorsque�l’utilisateur�consulte�iphone.html�la�première�fois .�Vous�vous�rappelez�sans�doute�que,�dans�les�précédents�exemples,�j’ai�vérifié�url == undefined�afin�de�gérer� le�chargement�de�la�première�page,�mais,�dans�cet�exemple,�nous�allons�utiliser�la�page�de�départ�à�plusieurs�endroits .�Il�est�donc�judicieux�de�la�définir�de�manière�globale .

�Cette�ligne�et�la�suivante�composent�la�définition�de�la�fonction�$(document).ready() .�Notez�qu’à� la�différence�des�précédents�exemples,� je� transmets� la�page�de�départ�à� la� fonction�loadPage() .

�Nous�voici�passés�à�la�fonction�loadPage() .�Cette�ligne�et� la�suivante�sont�identiques�aux�précédents�exemples .

�Cette� instruction�if...else�détermine� les�éléments�à�charger�dans� la�page�distante .�Par�exemple,�si�nous�souhaitons�la�page�de�démarrage,�nous�récupérons�les�ul�de�header .�Sinon,�nous�récupérons�la�div�content .

�Dans�cette� ligne,� le�paramètre�d’URL�et� l’élément� source�approprié� sont� concaténés� et�passés�comme�premier�paramètre�à� la�fonction�load .�Pour� le�second�paramètre,� je�passe�directement�une�fonction�anonyme�(une�fonction�sans�nom�qui�est�définie�à�l’intérieur) .�En�examinant�la�fonction�anonyme,�vous�constaterez�de�grandes�ressemblances�avec�la�fonction�hijackLinks()�qu’elle�est�venue�remplacer .�Les�trois�lignes�qui�suivent�sont�identiques�aux�précédents�exemples .

Stark Livre.indb 49 30/04/10 14:40

Page 21: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

50Applications iPhone avec HTML, CSS et Javascript

�Dans�cette�ligne,�je�supprime�l’objet�.leftButton�de�la�page�(cela�peut�sembler�étrange,�parce�que�je�ne�l’ai�pas�encore�ajouté�à�la�page,�mais�nous�le�ferons�quelques�étapes�plus�loin) .

�Ici,� j’utilise�la�méthode�prédéfinie�unshift�du�tableau�JavaScript�pour�ajouter�un�objet�au�début�du�tableau�hist .�L’objet�que�j’ajoute�possède�deux�propriétés,�url�et�title,�qui�sont�les�deux�éléments�d’information�dont�nous�avons�besoin�pour�prendre�en�charge�l’affichage�et�le�comportement�du�bouton�de�retour .

�Dans�cette�ligne,�j’utilise�la�méthode�prédéfinie�length�du�tableau�JavaScript�pour�détermi-ner�combien�d’objets�se�trouvent�dans�le�tableau�d’historique .�S’il�n’y�a�qu’un�objet�dans�le�tableau,�cela�signifie�que�l’utilisateur�se�trouve�sur�la�première�page,�si�bien�que�nous�n’avons�pas�besoin�d’afficher�un�bouton�de�retour .�S’il�y�a�plus�d’un�objet�dans�le�tableau�hist,�nous�devons�ajouter�un�bouton�à�l’en-tête .

�Ensuite,�j’ajoute�le�bouton�.leftButton�que�j’ai�mentionné�précédemment .�Le�texte�du�bouton�correspondra�au�titre�de�la�page�qui�précède�la�page�courante,�auquel�j’accède�avec�le�code�hist[1].title .�Les�tableaux�JavaScript�sont�indicés�à�partir�de�zéro,�si�bien�que�le�premier�élément�du�tableau�(la�page�courante)�possède�l’index�0 .�L’index�0�correspond�ainsi�à�la�page�courante,�l’index�1�à�la�page�précédente,�l’index�2�à�la�page�encore�antérieure,�et�ainsi�de�suite .

�Dans�ce�bloc�de�code,�je�lie�une�fonction�anonyme�au�gestionnaire�de�clic�du�bouton�Précé-dent .�Rappelez-vous�que�le�code�de�gestionnaire�de�clic�s’exécute�lorsque�l’utilisateur�clique,�et�non�lorsque�la�page�se�charge .�Ainsi,�une�fois�que�la�page�se�charge�et�que�l’utilisateur�clique�pour�revenir�en�arrière,�le�code�à�l’intérieur�de�cette�fonction�s’exécute .

�Cette�ligne�et�la�suivante�utilisent�la�méthode�prédéfinie�shift�du�tableau�pour�supprimer�les�deux�premiers�éléments�du�tableau�hist,�et�la�dernière�ligne�dans�la�fonction�envoie�l’URL�de�la�page�précédente�à�la�fonction�loadPage() .

�Les�lignes�qui�restent�sont�reprises�des�précédents�exemples ;�inutile�de�les�passer�en�revue�ici .

�Voici�le�code�de�correspondance�d’URL�présenté�précédemment�dans�ce�chapitre .�N’oubliez�pas�de�remplacer�jonathanstark.com�par�le�nom�de�domaine�ou�le�nom�d’hôte�de�votre�site�web,�sans�quoi�aucun�des�liens�locaux�ne�sera�détourné�et�chargé�dans�la�page .

InfoConsultez la page http://www.hunlock.com/blogs/Mastering_Javascript_Arrays pour une liste complète des fonctions de tableau JavaScript avec des descriptions et des exemples.

Maintenant�que�nous�disposons�d’un�bouton�de�retour,�il�ne�reste�plus�qu’à�modifier�son�appa-rence�avec�un�peu�de�CSS�(voir�exemple 3-11) .�Je�commence�par�mettre�en�forme�le�texte�avec�font-weight,�text-align,�lineheight,�color�et�text-shadow .�Je�continue�en�plaçant�la�div�préci-sément�où�je�le�souhaite�sur�la�page�avec�position,�top�et�left .�Ensuite,�je�m’assure�que�le�texte�long�sur�l’étiquette�du�bouton�est�tronqué�avec�des�points�de�suspension�en�utilisant�max-width,�white-space,�overflow�et�textoverflow .�Pour�finir,�j’applique�une�image�avec�border-width�et�-web-kit-border-image .�À�la�différence�de�mon�précédent�exemple�d’image�de�bordure,�cette�image-ci�

Stark Livre.indb 50 30/04/10 14:40

Page 22: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

51 Mise en forme iPhone avancée

Chapitre3

possède�une�largeur�différente�pour�les�côtés�gauche�et�droit,�car�elle�est�rendue�asymétrique�du�fait�que�la�flèche�pointe�vers�la�gauche .

InfoN’oubliez pas que vous aurez besoin d’une image pour ce bouton. Vous devrez l’enregistrer sous le nom back_button.png dans le dossier images du répertoire qui contient votre fichier HTML. Consultez la section « Ajouter un comportement simple avec jQuery » du chapitre 2 pour des astuces qui vous aideront à trouver ou créer vos propres images de bouton.

Exemple 3-11. Ajoutez le code suivant à iphone.css pour embellir le bouton de retour avec une image de bordure

#header div.leftButton { font-weight: bold; text-align: center; line-height: 28px; color: white; text-shadow: rgba(0,0,0,0.6) 0px -1px 0px; position: absolute; top: 7px; left: 6px; max-width: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-width: 0 8px 0 14px; -webkit-border-image: url(images/back_button.png) 0 8 0 14;}

Par�défaut,�Mobile�Safari�affiche�brièvement�une�boîte�grise�translucide�au-dessus�des�objets�cliquables�qui�ont�été�touchés�(voir�figure 3-7) .�Comme�notre�bouton�de�retour�n’est�pas�rec-tangulaire,�cet�effet�est�un�peu�bancal,�mais�on�peut�aisément�le�supprimer�et�donner�meilleure�apparence�à�l’application .�Mobile�Safari�prend�en�charge�une�propriété�nommée�-webkit-tap-highlight-color�qui�vous�permet�de�changer�la�couleur�par�défaut�en�la�remplaçant�par�celle�de�votre�choix .�Comme�jene�souhaite�pas�de�mise�en�valeur,�je�choisis�ici�une�couleur�entièrement�transparente�(voir�exemple 3-12) .

Exemple 3-12. Ajoutez ces lignes à iphone.css pour supprimer la mise en surbrillance de Mobile Safari

#header div.leftButton { font-weight: bold; text-align: center; line-height: 28px; color: white; text-shadow: rgba(0,0,0,0.6) 0px -1px 0px; position: absolute;

Stark Livre.indb 51 30/04/10 14:40

Page 23: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

52Applications iPhone avec HTML, CSS et Javascript

top: 7px; left: 6px; max-width: 50px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border-width: 0 8px 0 14px; -webkit-border-image: url(images/back_button.png) 0 8 0 14; -webkit-tap-highlight-color: rgba(0,0,0,0);}

Figure 3-7

Par défaut, Mobile Safari affiche un rectangle translucide gris par-dessus les objets cliquables sur lesquels l’utilisateur a déjà appuyé.

Dans�le�cas�du�bouton�de�retour,� il�peut�y�avoir�une�ou�deux�secondes�de�délai�avant�que�le�contenu�de�la�page�précédente�n’apparaisse .�Pour�éviter�toute�frustration,�je�souhaite�que�le bou-ton�ait�l’air�enfoncé�au�moment�où�l’on�appuie�dessus .�Dans�un�navigateur�de�bureau,�ce�processus�serait�simple ;�il�suffirait�d’ajouter�une�déclaration�aux�CSS�en�utilisant�la�pseudo-classe�:active�pour�spécifier�un�autre�style�pour�l’objet�cliqué .�Je�ne�sais�pas�s’il�s’agit�d’un�bogue�ou�d’un�choix�délibéré,�mais�cela�ne�fonctionne�pas�sur�l’iPhone .�Le�style�:active�est�ignoré .

Stark Livre.indb 52 30/04/10 14:40

Page 24: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

53 Mise en forme iPhone avancée

Chapitre3

Je�me�suis�amusé�avec�une�série�de�combinaisons�de�:active�et�:hover,�qui�m’ont�permis�d’arri-ver�à�mes�fins�avec�des�applications�non-Ajax .�Mais�avec�les�applications�Ajax�comme�celle�dont�il�est�question�ici,�le�style�:hover�reste�actif�après�coup�(autrement�dit,�le�bouton�semble�rester�cliqué�même�après�que�le�doigt�l’a�relâché) .

Heureusement,�le�correctif�est�assez�simple .�Avec�jQuery,�on�peut�ajouter�la�classe�clicked�au�bouton�lorsque�l’utilisateur�clique�dessus .�Pour�cet�exemple,�j’ai�choisi�d’appliquer�une�version�plus�sombre�de�l’image�du�bouton�(voir�figure 3-8�et�exemple 3-13) .�Assurez-vous�de�placer�une�image�de�bouton�appelée�back_button_clicked.png�dans�le�sous-dossier�images .�Consultez�la�sec-tion�« Ajouter�un�comportement�simple�avec�jQuery »�pour�des�astuces�qui�vous�permettront�de�trouver�ou�de�créer�vos�propres�images�de�bouton .

Figure 3-8

La différence est subtile, mais le bouton Précédent cliqué est un peu plus sombre que son état par défaut

Exemple 3-13. Ajoutez les lignes suivantes à iphone.css pour donner l’impression que le bouton Précédent est enfoncé quand l’utilisateur tape dessus

#header div.leftButton.clicked { -webkit-border-image: url(images/back_button_clicked.png) 0 8 0 14;}

Stark Livre.indb 53 30/04/10 14:40

Page 25: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

54Applications iPhone avec HTML, CSS et Javascript

InfoComme j’utilise une image pour le style cliqué, il est intéressant de la précharger. Sans cela, l’image du bouton non-cliqué disparaît la première fois que l’on appuie dessus alors que l’image de l’état cliqué est encore en train de se télécharger. Je traiterai du préchargement des images au chapitre suivant.

Une�fois�les�CSS�en�place,�je�peux�maintenant�mettre�à�jour�la�portion�d’iphone.js�qui�associe�le�gestionnaire�de�clic�au�bouton�de�retour .�Pour�commencer,�j’ajoute�une�variable�e�à�la�fonction�anonyme�afin�de�capturer�l’événement�de�clic�entrant .�Ensuite,�je�place�la�cible�événement�dans�un�sélecteur�jQuery�et� j’appelle�la�fonction�jQuery�addClass()�pour�attribuer�ma�classe�CSS�clicked�au�bouton :

$('#header .leftButton').click(function(e){ $(e.target).addClass('clicked'); var thisPage = hist.shift(); var previousPage = hist.shift(); loadPage(previousPage.url);});

InfoUne note spéciale pour les experts en CSS : la technique des sprites CSS (popularisée par A List Apart) ne peut être utilisée dans ce cas, parce qu’elle requiert de définir des décalages pour l’image. Or les décalages d’image ne sont pas pris en charge par la propriété -webkit-border-image.

Ajouter une icône à l’écran d’accueilAvec�un�peu�de�chance,�les�utilisateurs�souhaiteront�ajouter�une�icône�pour�votre�application�web�(appelée�« icône�de�clip�web »)�à�leur�écran�d’accueil .�Pour�cela,�ils�peuvent�appuyer�sur�le�bouton�+�en�bas�de�la�fenêtre�Safari�(voir�figure 3-9),�taper�sur�Ajouter�à�l’écran�d’accueil�(voir�figure 3-10)�et�cliquer�sur�le�bouton�Ajouter�(voir�figure 3-11) .�Par�défaut,� l’iPhone�crée�cette�icône�en�générant�une�vignette�de�la�page�courante�(avec�sa�position�et�son�niveau�de�zoom�actuels)�à�laquelle�il�applique�des�bords�arrondis�et�un�reflet�(voir�figure 3-12) .

Les�développeurs�à�la�page�se�piquent�toujours�de�personnaliser�l’image�de�l’écran�d’accueil�et,�pour�cela,�fournissent�une�icône�de�clip�web�personnalisée .�Le�moyen�le�plus�simple�de�procéder�consiste�à�spécifier�une�icône�pour�votre�site�entier�en�plaçant�un�fichier�nommé�apple-touch-icon.png�à�la�racine�du�site�web .�Le�fichier�doit�faire�57 pixels�sur�57,�sans�reflet�ni�bord�arrondi,�car�l’iPhone�les�ajoute�automatiquement .�Si�vous�ne�souhaitez�pas�que�l’iPhone�ajoute�des�effets�à�votre�icône�de�clip�web,�changez�le�nom�du�fichier�en�l’appelant�apple-touch-icon-precom-posed.png .

Stark Livre.indb 54 30/04/10 14:40

Page 26: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

55 Mise en forme iPhone avancée

Chapitre3

Figure 3-9

Ajout d’une icône de clip web à votre écran d’accueil, étape 1 : cliquez sur le bouton + en bas de la fenêtre Safari.

Figure 3-10

Étape 2 : cliquez sur le bouton Ajouter à l’écran d’accueil dans la boîte de dialogue.

Stark Livre.indb 55 30/04/10 14:40

Page 27: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

56Applications iPhone avec HTML, CSS et Javascript

Figure 3-11

Étape 3 : cliquez sur le bouton Ajouter dans le panneau Ajouter à l’accueil.

Figure 3-12

Étape 4 : une image de 57 × 57 pixels s’affiche sur l’écran d’accueil.

Dans�certains�cas,�il�peut�arriver�que�vous�souhaitiez�fournir�une�icône�de�clip�web�différente�pour�une�page�spécifique�du�site .�Vous�pouvez�le�faire�en�ajoutant�l’une�des�lignes�suivantes�à�la�section�head�de�notre�document�HTML�« agent�de�la�circulation »,�iphone.html�(en�remplaçant�myCustomIcon.png�par�le�chemin�absolu�ou�relatif�vers�l’image) :

<link rel="apple-touch-icon" href="myCustomIcon.png" /><link rel="apple-touch-icon-precomposed" href="myCustomIcon.png" />

InfoSi vous devez utiliser des images précomposées, optez pour un rayon d’arrondi de 10 pixels ou plus ; sans cela, l’iPhone arrondira les bords à 10 pixels. Dans un cas comme dans l’autre, l’utilisa-tion des images précomposées supprime entièrement le reflet.

Mode plein écranVous�aimeriez�récupérer�un�quart�de�l’espace�vertical�de�Mobile�Safari�(104 pixels,�pour�être�précis) ?�Ajoutez�la�ligne�suivante�à�la�section�head�du�document�« agent�de�circulation »�iphone.

Stark Livre.indb 56 30/04/10 14:40

Page 28: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

57 Mise en forme iPhone avancée

Chapitre3

html,�et�votre�application�web�s’affichera�en�mode�plein�écran�lorsqu’elle�sera�lancée�à�partir�de�son�icône�de�clip�web :

<meta name="apple-mobile-web-app-capable" content="yes" />

J’aurais�pu�traiter�de�cette�fonctionnalité�auparavant,�mais�elle�n’est�utile�qu’une�fois�que�vous�avez�détourné�tous�vos�liens�hypertextes�avec�Ajax .�Dès�qu’un�utilisateur�clique�sur�un�lien�non�détourné�–�qui�conduit�effectivement�vers�une�nouvelle�page�–�Mobile�Safari�lance�et�charge�la�page�normalement .�Ce�comportement�est�parfait�pour�l’exemple�avec�lequel�nous�avons�tra-vaillé,�parce�que�les�liens�externes�(Amazon,�Twitter,�Facebook,�etc .)�s’ouvrent�dans�Safari .

Changer la barre d’état Une� fois� que� vous� avez� ajouté� la� balise� méta� apple-mobile-web-app-capable,� vous� avez� la�possibilité�de�contrôler�la�couleur�de�l’arrière-plan�de�la�barre�d’état�de�20 pixels�en�haut�de�l’écran,�en�utilisant�la�balise�méta�apple-mobile-web-app-status-bar-style .�Par�défaut,�c’est�la�barre�d’état�grise�de�Safari,�mais�vous�pouvez�changer�sa�couleur�en�noir�(voir�figure 3-13) .�

Figure 3-13

Le mode plein écran offre environ 25 % d’espace écran supplémentaire et permet de personnaliser l’apparence de la barre d’état.

Stark Livre.indb 57 30/04/10 14:40

Page 29: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

58Applications iPhone avec HTML, CSS et Javascript

Vous�pouvez�également�la�rendre�noire�translucide,�pour�qu’elle�soit�partiellement�transparente,�ce�qui�la�supprime,�en�outre,�du�flot�du�document .�En�d’autres�termes,�votre�contenu�est�remonté�vers�le�haut�de�20 pixels�et�sous�la�barre�d’état�lorsque�la�page�se�charge,�si�bien�qu’il�peut�être�nécessaire�de�positionner�votre�en-tête�un�peu�plus�bas�pour�compenser :

<meta name="apple-mobile-web-app-status-bar-style" content="black" />

InfoLes changements de style de la barre d’état ne prendront effet que lorsque l’application sera lan-cée en mode plein écran.

Fournir une image de démarrage personnalisée Lorsqu’une�application�se�lance�en�mode�plein�écran,�l’utilisateur�en�voit�apparaître�une�capture�d’écran�pendant�que�la�première�page�se�charge .�Cet�effet�ne�me�plaît�pas�trop .�En�effet,�cela�donne�l’impression�que�l’on�peut�interagir�avec�l’application,�alors�qu’en�réalité,�si�on�appuie�sur�un�lien,�rien�ne�se�passe .�En�outre,�la�capture�d’écran�est�réalisée�à�partir�de�la�dernière�page�de�la�précédente�visite�de�l’utilisateur,�au�point�de�défilement�où�celui-ci�l’avait�laissée�–�pas�très�affriolant !

Heureusement,�Mobile�Safari�permet�de�définir�une�image�de�démarrage�qui�s’affichera�pen-dant�le�chargement�de�la�page .�Pour�ajouter�une�image�de�démarrage�personnalisée,�créez�un�fichier�PNG�de�320 × 460 pixels�et�placez-le�dans�le�même�répertoire�que�le�fichier�iphone.html .�Ensuite,�ajoutez�la�ligne�suivante�à�la�section�head�d’iphone.html�(et�remplacez�myCustomStartup-Graphic.png�par�le�chemin�absolu�ou�relatif�vers�votre�image) :

<link rel="apple-touch-startup-image" href="myCustomStartupGraphic.png" />

La�prochaine�fois�que�vous�lancez�votre�application�depuis�l’icône�de�clip�web,�le�comporte-ment�de�chargement�par�défaut�s’enclenche�pendant�que�la�nouvelle� image�personnalisée�se�télécharge .�L’image�de�démarrage�personnalisée�s’affiche�au�lancement�suivant�(figure 3-14) .

Ce que vous avez apprisDans�ce�chapitre,�vous�avez�appris�à�convertir�un�site�web�standard�en�une�application�Ajax�plein�écran,�avec�des�indicateurs�de�progression,�un�bouton�de�retour�intégré�dans�le�style�iPhone,�et�une�icône�de�clip�web�personnalisée .�Au�chapitre�suivant,�vous�allez�découvrir�comment�don-ner�vie�à�votre�application�en�ajoutant�des�animations�d’interface�utilisateur�natives .�Eh�oui,�le�moment�est�venu�de�s’amuser !

Stark Livre.indb 58 30/04/10 14:40

Page 30: iPhone - fnac-static.com · Si vous chargez dynamiquement des pages externes, le navigateur n’offre aucune indication concernant l’avancement du processus ou l’apparition d’éventuelles

59 Mise en forme iPhone avancée

Chapitre3

Figure 3-14

Chargement d’une image de démarrage personnalisée pour une application lancée en mode plein écran.

Stark Livre.indb 59 30/04/10 14:40