2. TIMING DE LA FORMATION
Timing journalier :
●
Matin :
09h00-10h30 : première partie
10h30-10h45 : pause
10h45-13h00 : seconde partie
●
Pause déjeuner
●
Après-midi :
14h00-15h30 : troisième partie
15h30-15h45 : pause
15h45-17h00 : quatrième partie
●
Questions libres.
Timing journalier :
●
Matin :
09h00-10h30 : première partie
10h30-10h45 : pause
10h45-13h00 : seconde partie
●
Pause déjeuner
●
Après-midi :
14h00-15h30 : troisième partie
15h30-15h45 : pause
15h45-17h00 : quatrième partie
●
Questions libres.
merci de signaler toute contrainte de temps sur cette période dès le début
3. PLAN DE LA FORMATION
Historique du web & standards
Nouveaux éléments & attributs
Le formulaires web forms
Les microformats (microdata)
Audio & vidéo
Dessin avec canvas
Géolocalisation
Interraction avec les fichiers
Drap & drop
Push de données
Web messaging
Web sockets
Web storage
Web sql
Web workers
Application hors ligne
Exemples de CSS3
Jquery par l'exemple
5. Historique
5
Pour mieux comprendre la transition que le Web vit en ce moment, voici un bref historique de ce changement de cap.
→ 1998 : En prônant les avantages du XML, le W3C décide de ne plus continuer le développement du HTML (qui en
est à la version 4.01) et élabore une première spécification du XHTML (v 1.0). Cette version est un amalgame de la
syntaxe du HTML et des normes et standards XML.
Ce fut une bonne décision, car le XML étant strict sur ses normes, ça met de l’avant le souci d’un code bien structuré
et d’une uniformité entre les sites Web.
→ 2006 : 8 ans après cette décision, le W3C la remet en question et commence à penser que le XML (et le XHTML)
n’est peut être pas la voie du futur en conception Web. Il décide donc de travailler sur une nouvelle spécification du
HTML tout en continuant l’évolution du XHTML (v2.0). Plusieurs groupes (Mozilla, Opera, Google, …) viennent à
travailler conjointement avec le W3C sur le HTML 5.
Fait à noter : certains individus n’ont jamais arrêté de travailler sur le HTML depuis 1998. Pour en savoir plus sur la
période 1998-2006, vous pouvez lire sur le groupe WHATWG (www.whatwg.org).
→ 2009 : Le W3C arrête complètement de travailler sur le XHTML v2.0 et toutes les ressources sont redirigées vers
le HTML 5. La philosophie est désormais : pureté du design, par-dessus l’idéologie d’être rétro-compatible Adieu le
XHTML ! Les navigateurs restent compatibles avec le XHTML, mais l’emphase est maintenant sur l’implémentation
des spécifications du HTML 5.
Actuellement, il y a 2 spécifications du HTML 5 qui sont développées en parallèle :
● la version du WHATWG
● la version du W3C
Les deux groupes travaillent « relativement » conjointement, mais ils divergent sur certains points. Si vous devez
choisir une spécification, je vous conseille celle du W3C, qui est moins expérimentale.
Les spécifications du HTML 5 évoluent constamment. Ceci explique même pourquoi WHATWG a même décidé de
supprimer le « 5 » de HTML 5. Les navigateurs doivent donc toujours regarder les changements aux spécifications
pour se mettre à jour.
6. Historique
Quelques dates à retenir :
– 1991 HTML
– 1994 HTML 2
– 1996 CSS 1 + JavaScript
– 1997 HTML 4
– 1998 CSS 2
– 1999 HTML 4.01
– 2000 XHTML 1
– 2002 Tableless design
– 2004 WHATWG
– 2005 AJAX
– 2007 XHTML 2 boudé
– 2007 Le W3C récupère les travaux du WHATWG
– 2009 Arrêt des travaux sur XHTML 2
– 2010 HTML 5 + JavaScript API + CSS 3
6
9. HTML 5
● <!DOCTYPE html>
& <meta charset="UTF-8">
● Nouvelles balises
● Balises vidéos et audio
● Nouveaux champs de
formulaire
● Nouveaux attributs notamment
autofocus, placeholder
● Certaines balises et attributs
dépréciés : frame, frameset, big,
font, center, acronym, ...
● Intégration de SVG
● MicroData
● ...
LES NOUVEAUX ELEMENTS
→ Nouvelles balises :
● <section>
● <header>/<footer>
● <nav>
● <article>
● <aside>
● <hgroup>
● <time>
● <canvas>
● <audio>/<video>
● Et d’autres…
10. CSS 3
● Multi-colonnes
● Bordures
● Gradients
● Webfonts
● Manipulation de texte
● Animations & transitions
● Flexible box model
● Nouveaux selecteurs
● Media Queries
● ...
LES NOUVEAUX ELEMENTS
11. JavaScript
● Geolocation
● WebWorkers
● WebSockets
● Orientation
● Notification
● sessionStorage & localStorage
● Web SQL database & IndexedDB
● ...
LES NOUVEAUX ELEMENTS
12. HTML 5 + JavaScript
● Canvas 2D
● Intégration audio et vidéo
● Mode offline
● Gestion de l'historique
● Edition de contenu
● Drag & Drop
● Custom data attribute
● ...
LES NOUVEAUX ELEMENTS
13. CSS 3 + JavaScript
● Selectors
● Classlist
LES NOUVEAUX ELEMENTS
14. WebGL
● Avant Chrome 9, lancer chrome avec --enable-webgl
● Sous Firefox 4, about:config puis enable for all sites
● Exemple depuis Learning WebGL
● Body Browser de Google
LES NOUVEAUX ELEMENTS
15. A Venir
● Contacts API
● Webcam (Capture API)
● Device Orientation API
● Calendar API
● Speech input
● ...
LES NOUVEAUX ELEMENTS
17. Nouveaux types d'entrées dans HTML5
Ce que nous connaissons aujourd'hui comme étant HTML5 Forms ou HTML5 Web Forms a démarré
sous le nom de Web Forms 2.0, une spécification pré-HTML5 créée par un groupe appelé WHATWG
(Web Hypertext Applications Technology Working Group).
La majeure partie du travail initial du WHATWG est devenue le point de départ ce que nous appelons
maintenant HTML5 et l'effort Web Forms 2.0 fait à présent partie de la spécification HTML5 officielle,
que vous pouvez consulter à l'adresse suivante : bit.ly/njrWvZ.
Une partie non négligeable de la spécification est consacrée à de nouveaux types et attributs de
contenu pour l'élément d'entrée, que vous trouverez à l'adresse suivante :
Comme je l'ai mentionné précédemment, la spécification introduit 13 nouveaux types d'entrées à
utiliser dans des formulaires : recherche, tél., url, e-mail, dateheure, date, mois, semaine, heure,
dateheure-locale, numéro, plage, couleur.
L'utilisation de ces nouveaux types est simple. Imaginons que je veuille insérer un nouveau champ
d'e-mail sur un formulaire de commande. Comme vous pouvez le voir sur la Figure 1, j'ai modifié la
page de commande du site Web de modèle Pâtisserie WebMatrix en lui ajoutant des champs, dont e-
mail.
LES WEBFORMS
18. La balise <input> en HTML4 possède les propriétés suivante :
Type Description
text A free-form text field, nominally free of line breaks.
password A free-form text field for sensitive information, nominally free of line breaks.
checkbox A set of zero or more values from a predefined list.
radio An enumerated value.
submit A free form of button initiates form submission.
file An arbitrary file with a MIME type and optionally a file name.
image A coordinate, relative to a particular image's size, with the extra semantic that it must be the
last value selected and initiates form submission.
hidden An arbitrary string that is not normally displayed to the user.
select An enumerated value, much like the radio type.
textarea A free-form text field, nominally with no line break restrictions.
button A free form of button which can initiates any event related to button.
Exemple de formulaire :
<form action="http://example.com/cgiscript.pl" method="post">
<p>
<label for="firstname">first name: </label>
<input type="text" id="firstname"><br />
<label for="lastname">last name: </label>
<input type="text" id="lastname"><br />
<label for="email">email: </label>
<input type="text" id="email"><br>
<input type="radio" name="sex" value="male"> Male<br>
<input type="radio" name="sex" value="female"> Female<br>
<input type="submit" value="send"> <input type="reset">
</p>
</form>
LES WEBFORMS
19. La balise <input> en HTML5 a évolué en incluant de nouvelles propriétés :
Type Description
datetime A date and time (year, month, day, hour, minute, second, fractions of a second) encoded
according to ISO 8601 with the time zone set to UTC.
datetime-local A date and time (year, month, day, hour, minute, second, fractions of a second) encoded
according to ISO 8601, with no time zone information.
date A date (year, month, day) encoded according to ISO 8601.
month A date consisting of a year and a month encoded according to ISO 8601.
week A date consisting of a year and a week number encoded according to ISO 8601.
time A time (hour, minute, seconds, fractional seconds) encoded according to ISO 8601.
number This accepts only numerical value. The step attribute specifies the precision, defaulting to 1.
range The range type is used for input fields that should contain a value from a range of numbers.
email This accepts only email value. This type is used for input fields that should contain an e-mail
address. If you try to submit a simple text, it forces to enter only email address in
email@eurogiciel.fr format.
url This accepts only URL value. This type is used for input fields that should contain a URL
address. If you try to submit a simple text, it forces to enter only URL address either in
http://www.eurogiciel.fr format or in http://example.com format.
Exemple de formulaire :
<form action="demo_form.asp" autocomplete="on">
First name:<input type="text" name="fname"><br>
Last name: <input type="text" name="lname"><br>
E-mail: <input type="email" name="email" autocomplete="off"><br>
<input type="submit">
</form>
LES WEBFORMS
20. Quelques exemples de formulaires :
<form>
<p><label>Customer name: <input></label></p>
<fieldset>
<legend> Pizza Size </legend>
<p><label> <input type=radio name=size> Small </label></p>
<p><label> <input type=radio name=size> Medium </label></p>
<p><label> <input type=radio name=size> Large </label></p>
</fieldset>
</form>
<form>
<p><label>Customer name: <input></label></p>
<fieldset>
<legend> Pizza Size </legend>
<p><label> <input type=radio name=size> Small </label></p>
<p><label> <input type=radio name=size> Medium </label></p>
<p><label> <input type=radio name=size> Large </label></p>
</fieldset>
<fieldset>
<legend> Pizza Toppings </legend>
<p><label> <input type=checkbox> Bacon </label></p>
<p><label> <input type=checkbox> Extra Cheese </label></p>
<p><label> <input type=checkbox> Onion </label></p>
<p><label> <input type=checkbox> Mushroom </label></p>
</fieldset>
</form>
LES WEBFORMS
27. Le microformat propose une syntaxe qui s’apparente à du HTML classique et s’applique bien en
dehors de la norme HTML5 puisqu’il est compatible avec HTML4, ou XHTML1.0 par exemple. Il utilise
l’attribut class et certaines valeurs bien précises dans le but de “baliser” un contenu afin qu’il soit
interprété comme une donnée bien spécifique.
Voici un exemple de code un peu plus parlant :
<span class="hreview-aggregate">
<span class="item">
<span class="fn">Juiz Smart Mobile Admin</span>
</span>
<span class="rating">
Note de :
<span class="average">90</span> sur
<span class="best">100</span>
</span>
basée sur
<span class="count">35</span> votes.
</span>
Comme vous pouvez le constater, les microformats n’utilisent pas d’attribut ou de syntaxe trop
complexe, seulement des valeurs de classe bien précises.
Vous trouverez un bon nombre de données et d’outils sur le site microformats.org qui a proposé une
tentative de codification des pratiques courantes. Microformats.org a ainsi pu réunir un certain nombre
de “profils” XMPD que vous trouverez directement sur le wiki microformats. En plus de simples
valeurs de classe, microformat c’est également l’utilisation de l’attribut rel, c’est le format hCard, le
format hCalendar, etc...
LES MICROFORMATS
28. Les microdonnées :
Les microdonnées sont représentées par l’arrivée de nouveaux attributs en HTML5.
Il est alors possible de donner la référence du document utilisé pour baliser l’information directement
au sein de l’élément porteur de ces informations.
Il faut attirer l'attention sur l’arrivée d’un document qui tend à devenir une nouvelle référence pour
structurer des données : issu d’un consortium entre Google, Bing, Yahoo et Yandex, cette référence
est nommée schema.org. Ce sont d’ailleurs les schémas proposés par schema.org.
LES MICROFORMATS
29. Nouveaux attributs :
Il n’en existe pas énormément :
● itemscope : il permet de créer un item dont le type peut-être précisé grâce à l’attribut suivant,
● itemtype : couplé à itemscope, il accueille une URL vers la référence du schéma (ex :
“http://schema.org/Review”) qui devra respecter les valeurs de ce schéma,
● itemprop : il est porteur d’une valeur permettant de préciser la nature d’une donnée au sein d’un
schéma spécifié précédemment.
● itemref : il permet de faire le lien complémentaire entre deux données sans descendance.
● itemid : lorsque l’item possède une référence globale unique, comme par exemple un l’identifiant d’un
livre (urn:isbn:0-xxx-xxxxx-x). Il est attribué en même temps que l’attribut itemscope.
Ces attributs peuvent être transportés par n’importe quel élément (souvent des span pour injecter une
donnée sans mise en forme particulière), bien que certaines exceptions, évidentes, existent.
Exemple d’une simple revue :
<span itemscope itemtype="http://schema.org/Review">
<span itemprop="itemReviewed">Juiz Smart Mobile Admin</span>
<span itemprop="reviewRating">
Note de : 90 sur 100
</span>
basée sur 35 votes.
</span>
Rendu :
“Juiz Smart Mobile Admin Note de : 90 sur 100 basée sur 35 votes.”
LES MICROFORMATS
30. Exemple d’une notation imbriquée dans une revue :
Aussi appelée Embedded Items, l’imbrication de différents types de schéma peut intervenir dans le cas de
notre exemple de revue. En effet, notre exemple précédent manque quelque peu de précision, puisque
schema.org prévoit également un type de schéma pour les évaluations :
<div itemscope itemtype="http://schema.org/Review">
<h1 itemprop="itemReviewed">Juiz Smart Mobile Admin</h1>
<!-- Imbrication d’un item -->
<p itemprop="reviewRating" itemscope itemtype="http://schema.org/AggregateRating">
Note de :
<span itemprop="ratingValue">90</span> sur
<span itemprop="bestRating">100</span>
basée sur
<span itemprop="ratingCount">35</span> votes.
</p>
<!-- / fin de l’imbrication -->
<p itemprop="reviewBody">
Ce plugin proposé pour optimiser l'interface d'administration de[…]
</p>
</div>
Rendu :
“Juiz Smart Mobile Admin
Note de : 90 sur 100 basée sur 35 votes.
Ce plugin proposé pour optimiser l’interface d’administration de[…]”
LES MICROFORMATS
31. Création d’une fiche « film » :
Je prends volontairement ce dernier exemple pour vous présenter une technique qui permet d’associer des
informations sans qu’elles soient forcément imbriquées. En effet il arrive que la mise en page d’un site web
ou l’évolution de ses informations ne permette pas d’imbriquer les items comme nous l’avons vu juste
avant.
La fiche film est divisée en deux mais ses informations sont réunies sous le même item grâce à la propriété
itemref qui fait référence à l’élément aside#more-info à travers son identifiant “more-info”.
LES MICROFORMATS
32. Cet attribut permet de présenter un même item découpé en plusieur éléments à travers la page. Si les
informations de notre item Movie avaient été disséminées dans d’autres éléments de la page, il aurait été
possible de les cibler grâce à la valeur de leur attribut id de la sorte :
<article itemscope itemtype="http://schema.org/Movie" itemref="more-info id2 id3 id4">
Je ne vous ai pas encore expliqué la présence des éléments meta dans la page. Ceux-ci permettent
d’insérer une information qui a souvent besoin d’un formatage précis qui est peu intelligible par une
personne non aguerrie.
Prenons l’exemple de l’information “duration” qui représente la durée. Cette information doit être formatée
en respectant le format ISO 8601 qui définit un format de date ou de temps.
Dans notre fiche, il aurait été possible d’écrire :
<dd itemprop="duration">PT91M</dd>
Mais vous imaginez bien ici que PT91M est quelque peu dérangeant pour définir une durée d’une heure et
demi. C’est pourquoi, par convention – et si ce n’en est pas encore une il faudrait que ça le devienne –
l’information s’écrit dans un élément meta et à côté de l’information intelligible.
LES MICROFORMATS
33. Le code HTML correspondant à cette mise en page pourrait ressembler à cela :
<section role="main">
<article itemscope itemtype="http://schema.org/Movie" itemref="more-info">
<h1 itemprop="name">Nom du film de la fiche</h1>
<img itemprop="image" src="img/the-film.png" alt="" width="150" height="150">
<section itemprop="video" itemscope itemtype="http://schema.org/VideoObject">
<h2>Trailer : <span itemprop="name">Nom du film de la fiche</span></h2>
<meta itemprop="duration" content="T1M33S">
<meta itemprop="thumbnail" content="image-miniature-du-trailer.jpg">
<object …>
<param …>
<embed type="application/x-shockwave-flash" …>
</object>
<p itemprop="description">Courte description de la vidéo</p>
</section>
<section itemprop="description">
<p>Contenu principal de ma fiche film</p>
</section>
<footer>
<dl>
<dt>Réalisateur</dt>
<dd itemprop="director">Emily Atef</dd>
<dt>Acteurs</dt>
<dd itemprop="actors">Maria-Victoria Dragus</dd>
<dd itemprop="actors">Roeland Wiesnekker</dd>
<dd itemprop="actors">Wolfram Koch</dd>
LES MICROFORMATS
37. L'élément <video>, cousin de <audio> offre en HTML5 une solution simple, native pour les
navigateurs pour l'intégration d'une vidéo dans une page web. Elle permet également de proposer
une alternative à l'utilisation de Flash pour les plate-formes ne le supportant pas (iOS par exemple
avec iPhone, iPod, iPad...).
La syntaxe de base de la balise video est extrêmement simple :
<video controls src="video.ogv">Ici la description alternative</video>
L'attribut src définit bien entendu l'adresse du fichier vidéo, tout comme pour la balise img lorsqu'il
s'agit d'une image. Si vous indiquez les dimensions avec les attributs height et width, c'est encore
mieux, et si tout va bien, un élément devrait s'afficher dans le navigateur... pour peu que celui-ci
supporte le format de vidéo indiqué dans la source.
AUDIO & VIDEO
38. On peut également proposer plusieurs sources dans plusieurs formats différents en indiquant les
types MIME grâce à l'attribut type :
<video width="400" height="222" controls="controls">
<source src="video.mp4" type="video/mp4" />
<source src="video.webm" type="video/webm" />
<source src="video.ogv" type="video/ogg" />
Ici l'alternative à la vidéo : un lien de téléchargement, un message, etc.
</video>
Les navigateurs ne pouvant pas lire le MP4/H.264 ni la version WebM nativement (comme Firefox 3.6
par exemple) prendront la version au format Ogg Theora. Cela vous oblige néanmoins à encoder le
fichier avec différents codecs.
Particularité de la syntaxe XHTML : il faut ajouter controls="controls" (et pas juste controls comme
vous pourrez le voir sur le premier exemple) pour afficher les possibilités de contrôle de la vidéo. Ceci
est valable pour tous les attributs (autoplay, etc.).
AUDIO & VIDEO
39. ● Attributs :
L'attribut controls donne accès aux contrôles de lecture (boutons de navigation, volume, etc, selon les
possibilités du navigateur), ou les masque s'il est omis.
L'attribut preload="auto" permet de de spécifier au navigateur de débuter le téléchargement de la
vidéo tout de suite, en anticipant sur le fait que l'utilisateur lira la vidéo. Attention, cette option est à
manier avec prudence (il est préférable que ce soit la seule raison d'être de la page). Note : il s'agit de
l'ancien attribut autobuffer qu'il vous faudra laisser pour Firefox 3.5 et 3.6.
L'attribut autoplay="true" comme son nom l'indique, permet de lancer la lecture automatiquement.
Cela peut également être problématique avec une connexion à faible bande passante ou sur un
terminal mobile. De manière générale, évitez d'imposer vos choix à l'utilisateur... et à sa connexion
internet.
L'attribut poster="image.jpg" permet d'indiquer une image à afficher par défaut dans l'espace réservé
par la vidéo, avant que la lecture de celle-ci ne soit lancée.
L'attribut loop indique que la lecture doit s'effectuer en boucle.
● Prérequis :
Pensez également à préciser les types MIME dans un fichier .htaccess pour être sûr qu'ils soient
corrects, les trois lignes suivantes suffisent à s'assurer la tranquilité :
AddType video/ogg .ogv
AddType video/mp4 .mp4
AddType video/webm .webm
AUDIO & VIDEO
40. ● Formats :
Plusieurs formats tiennent le devant de la scène : WebM, MP4 et Ogg Theora. Même si le but de ce
tutoriel est de proposer une solution d'intégration de la balise video compatible sur le plus de
navigateurs possible (et pas de discuter du choix des formats dans un interminable débat), faisons
quand même une présentation rapide.
→ H.264/MP4 :
H.264 est supporté par le Moving Picture Experts Group. C'est un format non-libre (soumis à brevets)
et non-gratuit. Toutefois, il est gratuit dans certaines utilisations (la diffusion gratuite de vidéos par des
sites Web par exemple).
Les fichiers MP4 utilisant H.264 sont lisibles nativement sur les navigateurs Apple (Safari, Safari
Mobile) ainsi que sur Google Chrome.
AUDIO & VIDEO
41. → OGG/Theora :
Theora est un format de compression vidéo open-source, sans brevets. Ceci donne le droit à tous
d'utiliser Theora (à des fins non commerciales tout comme à des fins commerciales) sans devoir
payer de redevance au consortium MPEG.
OGG/Theora est lisible sur Firefox, Opéra, et Google Chrome.
AUDIO & VIDEO
42. AUDIO & VIDEO
→ WebM/VP8 :
WebM est un format multimédia ouvert qui a été lancé par Google (après rachat de la société On2
Technologies). L'utilisation est en libre et gratuite.
Comme on peut le constater, il y a une grande disparité dans le support des codecs, chacun
défendant ses intérêts pour le meilleur ou pour le pire (commerciaux ou libres).
43. AUDIO & VIDEO
●
Liens :
– http://diveintohtml5.info/video.html
– http://fr.wikipedia.org/wiki/Theora
– http://www.videojs.com/
–
45. Introduit à l'origine par Apple pour être utilisé dans WebKit pour des logiciels comme Dashboard et le
navigateur Safari, canvas a été par la suite adopté par les navigateurs utilisant Gecko (notamment
Mozilla Firefox) et Opera, avant d'être standardisé par le groupe de travail WHATWG. Novell a
développé une extension activant les XForms dans Internet Explorer1 offrant ainsi une prise en
charge des fonctionnalités de canvas.
<canvas id="mon_canvas" width="350" height="350">
Texte alternatif pour les navigateurs ne supportant pas Canvas.
</canvas>
À partir de ce moment, tout se passe du côté de JavaScript, qui va se servir de cet élément HTML
pour accéder à la surface de dessin. Pour ceci, deux fonctions sont appelées :
getElementById() qui va permettre d'aller chercher et cibler l'élément <canvas> identifié par son
attribut id unique (ici mon_canvas),puis la méthode getContext() de l'élément ainsi récupéré pour
savoir dans quel contexte de dessin (2D ou 3D) le script va pouvoir agir, et de quelles fonctions il
pourra disposer. Le contexte sera l'élément central de gestion de Canvas.
<script type="text/javascript">
var c = document.getElementById("mon_canvas");
var ctx = c.getContext("2d");
// Dessine un rectangle rouge
ctx.fillStyle = 'red';
ctx.fillRect(30, 30, 50, 50);
</script>
Canvas
46. Tous les exemples suivants dans ce tutoriel feront appel à cette structure (élément Canvas +
élément script + appel à getElementById + getContext) qui ne sera pas reprécisée à chaque
fois.
Après cette étape préliminaire de mise en place, il faut se plonger dans l'ensemble des
méthodes de dessin 2D.
Celles-ci vont toutes exploiter le même système de coordonnées :
● Le point de référence (0,0) est situé en haut à gauche ;
● L'axe horizontal (x) est défini par la première coordonnée ;
● L'axe vertical (y) est défini par la seconde coordonnée ;
● Ces valeurs correspondent à la grille entourant les pixels, et non pas aux pixels eux-
mêmes.
Par exemple le point de coordonnées (4,2) sera situé 4 pixels à droite du coin supérieur
gauche, et 2 pixels en-dessous.
Canvas
Si l'on trace un polygone entre les 3 points présents sur ce schéma, on obtiendra un triangle.
47. Pour commencer, voici un exemple simple qui dessine deux rectangles ayant une intersection, l'un
d'entre-eux possédant une transparence alpha :
<html>
<head>
<script type="application/x-javascript">
function draw()
{
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect (30, 30, 55, 50);
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300" height="300"></canvas>
</body>
</html>
La fonction draw récupère l'élément canvas, et ensuite son contexte 2d. L'objet ctx peut ensuite être
utilisé pour dessiner réellement vers le canevas. L'exemple remplit simplement les deux rectangles, en
positionnant fillStyle à deux couleurs différentes à l'aide des spécifications de couleur CSS et d'un appel à
fillRect. Le second appel à fillStyle utilise rgba() pour spécifier une valeur alpha parmi les informations de
couleur.
Les appels à fillRect, strokeRect et clearRect affichent un rectangle plein, surligné ou vide. Pour afficher
des formes plus complexes, on utilise des chemins.
Canvas
48. La fonction beginPath commence un nouveau chemin, et moveTo, lineTo, arcTo, arc et des méthodes
similaires sont utilisées pour ajouter des segments au chemin. Le chemin peut être fermé à l'aide de
closePath. Une fois que le chemin est créé, vous pouvez utiliser fill ou stroke pour afficher celui-ci sur le
canevas.
<html>
<head>
<script type="application/x-javascript">
function draw()
{
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
ctx.beginPath();
ctx.moveTo(30, 30);
ctx.lineTo(150, 150);
ctx.bezierCurveTo(60, 70, 60, 70, 70, 150);
ctx.lineTo(30, 30);
ctx.fill();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300" height="300"></canvas>
</body>
</html>
L'appel à fill() ou stroke() provoque l'utilisation du chemin. Pour être rempli ou dessiné à nouveau, le
chemin devra être recréé.
Canvas
52. Une des nouveautés introduites par HTML5 est la géolocalisation utilisable via une
API d'un navigateur.
Cela permet aux pages web d'interroger le navigateur sur la position géographique
de l'utilisateur.
L'API de base permet d'obtenir les coordonnées en latitude et en longitude ainsi
que l'altitude.
Celles-ci peuvent alors être exploitées par le biais d'une carte (de type Google
Map).
Détection du support :
if (navigator.geolocation)
{
//le navigateur supporte la géolocalisation
//suite du code ici
} else {
alert('Votre navigateur ne supporte pas la géolocalisation HTML5');
}
Géolocalisation
53. Détail de la méthode getCurrentPosition() :
PropertyProperty DescriptionDescription
coords.latitude The latitude as a decimal number
coords.longitude The longitude as a decimal number
coords.accuracy The accuracy of position
coords.altitude The altitude in meters above the mean sea level
coords.altitudeAccuracy The altitude accuracy of position
coords.heading The heading as degrees clockwise from North
coords.speed The speed in meters per second
timestamp The date/time of the response
Géolocalisation
54. Exemple de code pour un client :
<script>
var x = document.getElementById("demoLoc");
function getLocation()
{
if (navigator.geolocation)
{
navigator.geolocation.getCurrentPosition(showPosition);
} else{
x.innerHTML="Geolocation is not supported by this browser.";}
}
function showPosition(position)
{
x.innerHTML="Latitude:"+position.coords.latitude + "<br>Longitude: " + position.coords.longitude;
}
</script>
Géolocalisation
55. Gestion des erreurs :
function showError(error)
{
switch(error.code)
{
case error.PERMISSION_DENIED:
x.innerHTML="User denied the request for Geolocation."
break;
case error.POSITION_UNAVAILABLE:
x.innerHTML="Location information is unavailable."
break;
case error.TIMEOUT:
x.innerHTML="The request to get user location timed out."
break;
case error.UNKNOWN_ERROR:
x.innerHTML="An unknown error occurred."
break;
}
}
Code d'erreurs :
● Permission denied : l'utilisateur n'est pas autorisé pour utiliser la géolocalisation
● Position unavailable : géolocalisation impossible
● Timeout : timeout pour aller jusqu'au bout de la géolocalisation
Géolocalisation
56. Example d'affichage de la position sur une carte :
function showPosition(position)
{
var latlon = position.coords.latitude+","+position.coords.longitude;
var img_url = "http://maps.googleapis.com/maps/api/staticmap?center="
+latlon+"&zoom=14&size=400x300&sensor=false";
document.getElementById("mapholder").innerHTML="<img src='" + img_url + "'>";
}
Géolocalisation
57. Autre méthodes :
● watchPosition() : retourne la position courante ainsi que le mouvement via une icône
(voiture).
● clearWatch() : arrête la méthode watchPosition
Example d'utilisation de la méthode watchPosition :
<script>
var x = document.getElementById("demo");
function getLocation()
{
if (navigator.geolocation)
{
navigator.geolocation.watchPosition(showPosition);
} else {
x.innerHTML="Geolocation is not supported by this browser.";
}
}
function showPosition(position)
{
x.innerHTML="Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
</script>
Géolocalisation
60. L'API offerte aux navigateur web pour gérer les fichiers permet:
● De gérer une liste de fichiers (1:n) sélectionnable depuis la balise <input
type="file">
● Gestion de fichiers raw de type binaires avec autorisations d'accès d'une zone
d'octets
● Une interface détaillant le nom du(des) fichier(s), leur type et leur URL
● Une interface permettant de lire un fichier
● Une gestion d'exception permettant la gestion des exceptions
Gérer les fichiers
61. Vérifier le support disponible :
if (window.File && window.FileReader && window.FileList && window.Blob)
{
// Accès possible
} else {
alert('The File APIs are not fully supported in this browser.');
}
Création d'un handle sur un fichier :
// Récupère le path + nom du fichier
var file = document.forms['uploadData']['fileChooser'].files[0];
// Autre moyen de récupérer le path + nom du fichier
// var file = document.forms['uploadData']['fileChooser'].files.item(0);
if (file) // ou if (file != undefined)
{
// Traitements sur le fichier . . .
}
Gérer les fichiers
62. Soit le code HTML suivant :
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
Voici un exemple de code
gérant les fichiers :
<script>
function handleFileSelect(evt)
{
var files = evt.target.files;
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++)
{
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'</li>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
Gérer les fichiers
Création d'un handle sur un fichier :
// Récupère le path + nom du fichier
var file = document.forms['uploadData']['fileChooser'].files[0];
// Autre moyen de récupérer le path + nom du fichier
// var file = document.forms['uploadData']['fileChooser'].files.item(0);
if (file) // ou if (file != undefined)
{
// Traitements sur le fichier . . .
}
63. Soit le code HTML suivant :
<div id="drop_zone">Drop files here</div>
<output id="list"></output>
Voici un exemple de code gérant les fichiers déposé en drag/drop :
<script>
function handleFileSelect(evt)
{
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files;
var output = [];
for (var i = 0, f; f = files[i]; i++)
{
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
f.size, ' bytes, last modified: ',
f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
'</li>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
Gérer les fichiers
65. A aprtir du code html & css suivant :
<style>
.thumb
{
height: 75px;
border: 1px solid #000;
margin: 10px 5px 0 0;
}
</style>
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
Le code JS permettant de lire le fichier est le suivant :
<script>
function handleFileSelect(evt)
{
var files = evt.target.files; // FileList object
for (var i = 0, f; f = files[i]; i++)
{
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
Gérer les fichiers
71. <input type="file" id="files" name="file" />
<button onclick="abortRead();">Cancel read</button>
<div id="progress_bar"><div class="percent">0%</div></div>
Le code Javascript permettant de monitorer la progression de la lecture d'un fichier est le
suivant :
<script>
var reader;
var progress = document.querySelector('.percent');
function abortRead()
{
reader.abort();
}
function errorHandler(evt)
{
switch(evt.target.error.code) {
case evt.target.error.NOT_FOUND_ERR:
alert('File Not Found!');
break;
case evt.target.error.NOT_READABLE_ERR:
alert('File is not readable');
break;
case evt.target.error.ABORT_ERR:
break; // noop
default:
alert('An error occurred reading this file.');
};
}
Gérer les fichiers
72. (...)
function updateProgress(evt)
{
// evt is an ProgressEvent.
if (evt.lengthComputable)
{
var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
// Increase the progress bar length.
if (percentLoaded < 100)
{
progress.style.width = percentLoaded + '%';
progress.textContent = percentLoaded + '%';
}
}
}
function handleFileSelect(evt)
{
// Reset progress indicator on new file selection.
progress.style.width = '0%';
progress.textContent = '0%';
reader = new FileReader();
reader.onerror = errorHandler;
reader.onprogress = updateProgress;
reader.onabort = function(e)
{
alert('File read cancelled');
};
reader.onloadstart = function(e)
{
document.getElementById('progress_bar').className = 'loading';
};
Gérer les fichiers
73. (...)
reader.onload = function(e)
{
// Ensure that the progress bar displays 100% at the end.
progress.style.width = '100%';
progress.textContent = '100%';
setTimeout("document.getElementById('progress_bar').className='';", 2000);
}
// Read in the image file as a binary string.
reader.readAsBinaryString(evt.target.files[0]);
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
Gérer les fichiers
74. Autre exemple :
var file = document.getElementById('file').files[0];
if (file)
{
// create an identical copy of file
// the two calls below are equivalent
var fileClone = file.slice();
var fileClone2 = file.slice(0, file.size);
var fileChunkFromEnd = file.slice(-(Math.round(file.size/2)));
var fileChunkFromStart = file.slice(0, Math.round(file.size/2));
// slice file from beginning till 150 bytes before end
var fileNoMetadata = file.slice(0, -150, "application/experimental");
}
Gérer les fichiers
75. Création d'un objet blob (Binary Large Object) :
var a = new Blob();
// Creation d'un tableau de 10.24 octets
var buffer = new ArrayBuffer(1024);
var shorts = new Uint16Array(buffer, 512, 128);
var bytes = new Uint8Array(buffer, shorts.byteOffset + shorts.byteLength);
var b = new Blob([toNativeLineEndings("foobarbazetcetc" + "birdiebirdieboo")], {type:
"text/plain;charset=UTF-8"});
var c = new Blob([b, shorts]);
var a = new Blob([b, c, bytes]);
var d = new Blob([buffer, b, c, bytes]);
Gérer les fichiers
78. Créer un élément pouvant être déplacé :
Pour rendre un élément déplaçable, il suffit de lui ajouter l'attribut «draggable » à
true:
<img id="drag1" src="img_logo.gif" draggable="true"
ondragstart="drag(event)" width="336" height="69">
L'attribut draggable positionné à True permet donc d'activer le drag & drop vis à vis
de l'image avec l'id « drag1 ».
Drag & drop
79. Créer un élément conteneur pouvant reçevoir un élément à déplacer:
Pour définir un conteneur, il faut définir 2 callbacks sur les évènements ondrop et
ondragover :
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
Il faudra définir dans le HEAD de la page un style pour le div :
<style type="text/css">
#div1 { width:350px;height:70px;padding:10px;border:1px solid #aaaaaa; }
</style>
Les dimensions sont compatible avec les dimensions de l'image pouvant être déplacer
dans le div.
Drag & drop
80. Exemple d'implémentation des callbacks de gestion des évenements ondrop et
ondragover :
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
Drag & drop
81. Drag & drop
●
Liens :
– http://html5demos.com/drag
– http://html5demo.braincracking.org/demo/dragNDrop.php
– http://www.startyourdev.com/codes/code-drag-drop.php
– http://chez-syl.fr/2012/03/drag-and-drop-html5-jquery/
– http://www.html5rocks.com/en/tutorials/dnd/basics/
83. Une des raisons pour lesquels les SSE ont été maintenus dans l'ombre, c'est que
des API comme les Web Sockets fournissaient déjà un protocole riche et bi-
directionnel en duplex intégral.
Avoir un canal bidirectionnel est plus attrayant pour des choses comme des jeux,
des applications de messagerie, et pour le cas où vous avez besoin à proximité de
mises à jour en temps réel dans les deux sens.
Toutefois, dans certains scénarios de données n'a pas besoin d'être envoyé par le
client. Vous devez simplement mises à jour de certaines mesures du serveur.
Quelques exemples seraient état des mises à jour amis, cours de la Bourse, les fils
de nouvelles, ou d'autres mécanismes d'incitation automatisée de données (par
exemple, mettre à jour une base de données SQL Web côté client ou un magasin
d'objets IndexedDB).
Si vous avez besoin d'envoyer des données à un serveur, l'objet XMLHttpRequest
est utile.
Push server
PUSH
mono-directionnel
84. Les SSE sont envoyés via du HTTP1.1 traditionnel.
Cela signifie qu'ils n'ont pas besoin d'un protocole spécifique ou la mise en œuvre
de serveur pour obtenir de travail.
Les Web Sockets d'autre part, nécessitent des connexions en duplex intégral et des
serveurs de sockets Web dédiés pour gérer ce protocole.
En outre, les Server-Sent Events ont une variété de caractéristiques qui manque
aux Web sockets tel que :
● la reconnexion automatique ;
● les événements associés à un ID ;
● la possibilité d'envoyer des événements arbitraires
Push server
85. Exemple d'enregistrement sur un flux d'évènements serveur :
Cela revient à instancier un objet EventSource avec l'url du flux :
if (!!window.EventSource)
{
var source = new EventSource('stream.php');
} else {
// Result to xhr polling
}
Push server
86. Ensuite, il faut déclarer un handle de message pour chaque événement :
source.addEventListener('message', function(e)
{
console.log(e.data);
}, false);
source.addEventListener('open', function(e)
{
// Connection was opened.
}, false);
source.addEventListener('error', function(e)
{
if (e.readyState == EventSource.CLOSED)
{
// Connection was closed.
}
}, false);
Push server
87. Il est possible que le serveur envoie des données complexes sous format json :
data: {n
data: "msg": "hello world",n
data: "id": 12345n
data: }nn
Pour ce faire, un handle de message sera rajouté et le message sera parsé pour
reformer l'objet au format de type json :
source.addEventListener('message', function(e)
{
var data = JSON.parse(e.data);
console.log(data.id, data.msg);
}, false);
Le JSON (JavaScript Object Notation) peut et doit être vu comme une structure de
Données, ou le résultat d'une sérialiation d'objet.
Push server
88. Pour des messages plus complexes :
data: {"msg": "First message"}nn
event: userlogonn
data: {"username": "John123"}nn
event: updaten
data: {"username": "John123", "emotion": "happy"}nn
Le traitement sera le suivant :
source.addEventListener('message', function(e)
{
var data = JSON.parse(e.data);
console.log(data.msg);
}, false);
source.addEventListener('userlogon', function(e)
{
var data = JSON.parse(e.data);
console.log('User login:' + data.username);
}, false);
source.addEventListener('update', function(e)
{
var data = JSON.parse(e.data);
console.log(data.username + ' is now ' + data.emotion);
}, false);
Push server
89. Coté serveur une implémentation en PHP est la suivante :
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
/**
* Constructs the SSE data format and flushes that data to the client.
*
* @param string $id Timestamp/id of this connection.
* @param string $msg Line of text that should be transmitted.
*/
function sendMsg($id, $msg)
{
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));
?>
Push server
90. Autre implémentation en Node.js :
var http = require('http');
var sys = require('sys');
var fs = require('fs');
http.createServer(function(req, res)
{
//debugHeaders(req);
if (req.headers.accept && req.headers.accept == 'text/event-stream')
{
if (req.url == '/events')
{
sendSSE(req, res);
} else {
res.writeHead(404);
res.end();
}
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(fs.readFileSync(__dirname + '/sse-node.html'));
res.end();
}
}).listen(8000);
Push server
91. function sendSSE(req, res)
{
res.writeHead(200,
{
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
var id = (new Date()).toLocaleTimeString();
// Sends a SSE every 5 seconds on a single connection.
setInterval(function()
{
constructSSE(res, id, (new Date()).toLocaleTimeString());
}, 5000);
constructSSE(res, id, (new Date()).toLocaleTimeString());
}
Push server
92. Le fichier sse-node.html aura le contenu suivant :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<script>
var source = new EventSource('/events');
source.onmessage = function(e)
{
document.body.innerHTML += e.data + '<br>';
};
</script>
</body>
</html>
Push server
93. Web socket (WS) vs évènements (SSE pour Server-Sent Events) envoyé depuis le serveur :
Advantages de SSE opposé aux Web sockets:
● Tranport via http au lieu d'un protocole dédié ;
● Peut être quand même utilisé via un backport sur des navigateurs ne disposant pas du
support ;
● Support intégré incluant des re-connexions et event-id
● Portocol simple
Advantages des Web sockets opposé aux SSE :
● Communication temps réelle et bi-directionnelle
● Support natif de plusieurs navigateur web
Utilisation idéale des SSE :
● Alimentation de données en continue ;
● Mise à jour des données twitter, fb, chat, … ;
● Notification serveur->browser
Push server
SSE WEB SOCKETS
97. Soit une page web contenant une iframe, on récupère son handle de la façon
suivante :
var o = document.getElementsByTagName('iframe')[0];
Ensuite on peut lui envoyer un message :
o.contentWindow.postMessage('Hello world',
'http://b.example.org/');
Web messaging
98. Web messaging
L'iframe pourra traiter le message via la callback suivante :
window.addEventListener('message', receiver, false);
function receiver(e)
{
if (e.origin == 'http://example.com')
{
if (e.data == 'Hello world')
{
e.source.postMessage('Hello', e.origin);
} else {
console.log(e.data);
}
}
}
99. Web messaging
●
Liens :
– http://www.w3.org/TR/webmessaging/
– http://en.wikipedia.org/wiki/Web_Messaging
– http://dev.opera.com/articles/view/window-postmessage-messagec
– http://msdn.microsoft.com/fr-fr/library/ie/hh781494(v=vs.85).aspx
– http://fr.slideshare.net/miketaylr/html5-web-messaging-7970364
– http://fr.slideshare.net/miketaylr/html5-web-messaging-7970364
–
101. Web sockets
●
Architecture :
101
Connexion persistante
serveurclient database
La connexion client/serveur :
- permet une communication « temps réel » pour des applications genre chat,
cours de bourse, … ;
- permet aux serveurs d'envoyer des évènements ;
- ouvert à l'initiative du client et reste ouvert par la suite ;
- le serveur doit supporter un certain nombre de sockets (1 par client)
data
109. Web storage
Cookies limités à quelques ko contre quelques Mo pour les storages
Ajout de deux interfaces/objets de stockage :
→ Stockage de session sessionStorage :
L'interface sessionStorage mémorise les données sur la durée d'une session de
navigation, et sa portée est limitée à la fenêtre ou l'onglet actif.
Lors de sa fermeture, les données sont effacées. Contrairement au cookies,
il n'y a pas d'interférence. Chaque stockage de session est limité à un domaine
→ Stockage local localStorage :
L'interface localStorage mémorise les données sans limite de durée de vie.
Contrairement à sessionStorage, elles ne sont pas effacées lors de la fermeture
d'un onglet ou du navigateur. La portée de localStorage est de facto plus large :
il est possible de l'exploiter à travers plusieurs onglets ouverts pour le même
domaine ou plusieurs fenêtres ; à partir du moment où il s'agit bien sûr du même
Navigateur.
Il n'y a pas de partage des données Web Storage entre les différents navigateurs qui
peuvent être installés sur une même machine.
110. Web storage
Usages et précautions
Le stockage de données dans le navigateur web se prête à différentes applications,
particulièrement lorsqu'il s'agit d'exécuter des traitements sans faire intervenir le serveur,
ou lorsqu'il faut mémoriser facilement de petites quantités de données pour l'utilisateur
pour les faire persister durant sa navigation. Parmi ces avantages :
● stocker rapidement des données en cache sans faire intervenir le serveur (par
exemple via AJAX),
● augmenter la performance ressentie et faciliter les développements,
● se passer des cookies et du trafic HTTP supplémentaire qu'ils représentent (un cookie
est envoyé à chaque requête effectuée sur un domaine),
● exploiter un espace alloué plus important que la limite imposée par les cookies (fixée à
4 Ko),
● retrouver des données immédiatement à la reconnexion ou les mémoriser pour éviter
la perte s'il y a déconnexion.
Attention : les données ne sont pas cryptées, accessibles facilement à tout utilisateur ayant accès au navigateur, et modifiables de la
même façon. Il ne faut donc pas y placer d'informations sensibles.
Pour ces raisons et d'autres, certains navigateurs exigent de consulter la page appelant le stockage via un domaine, (c'est-à-dire avec
une url en http://, que ce soit localhost ou bien un nom de domaine complet) et non pas en fichier local (adresse file://). Sinon, une
exception de sécurité peut être déclenchée. Ceci peut sembler logique car les données sont en théorie attachées à un domaine.
111. Web storage
Hormis les spécificités concernant la persistance des données, les méthodes d'accès sont communes :
● setItem(clé,valeur) : stocke une paire clé/valeur
● getItem(clé) : retourne la valeur associée à une clé
● removeItem(clé) : supprime la paire clé/valeur en indiquant le nom de la clé
● key(index): retourne la clé stockée à l'index spécifié
● clear(): efface toutes les paires
Pour agrémenter le tout, la propriété .length renvoie le nombre de paires stockées.
La console Javascript des navigateurs est un outil essentiel pour tester et vérifier le bon fonctionnement de Web Storage.
Accès aux données :
Note : Les exemples suivants se basent sur sessionStorage mais fonctionneront de la même façon avec localStorage.
112. Web storage
Stockage :
sessionStorage.setItem("couleur","vert")
Le premier argument de setItem est la clé (toujours de type String). Elle précise
l'endroit où sont stockées les données afin de pouvoir les y retrouver ultérieurement.
Récupération :
var couleur = sessionStorage.getItem("couleur");
Grâce à la clé initialement créée avec setItem il est possible de récupérer facilement
les données. Ces dernières sont renvoyées sous la forme d'une chaîne de caractère.
Suppression :
sessionStorage.removeItem("couleur");
Nous supprimons l'élément de session "couleur".
Suppression totale :
sessionStorage.clear();
Suppression complète de toutes les valeurs de session.
Accès direct :
Dans la plupart des situations, les variables seront accessibles directement en tant
que membres de l'interface.
sessionStorage.couleur = "vert";
console.log(sessionStorage.couleur);
114. Web storage
Une première application peut être la mémorisation de champs de formulaire, pour stocker les données
entrées par l'utilisateur. Bien que ceci soit applicable à toute variable manipulée en JavaScript.
Pour ceci, l'événement change sur <textarea> est sollicité pour stocker la valeur courante de l'élément
dans sessionStorage.message :
<textarea id="message" name="message"
onchange="sessionStorage.message=this.value"></textarea>
Notez que cette façon de faire est très compacte mais n'est pas des plus
esthétiques car le code JavaScript se retrouve "mélangé" au contenu HTML de la
page.
Ce script doit être placé en fin de document :
<script>
// Détection du support du storage
if(typeof sessionStorage!='undefined')
{
// Vérifie si la variable message a été stoquée dans les sessionStorage :
if('message' in sessionStorage)
{
$('textarea#message').text() = sessionStorage.getItem('message');
}
} else {
console.log("sessionStorage n'est pas supporté");
}
</script>
http://www.codegateway.com/2012/03/get-textarea-value-in-jquery.html
Exemple n° 1 :
115. Un deuxième exemple très simple à mettre en place est celui d'un compteur de visites.
<p>Vous avez vu cette page <span id="visites"></span> fois</p>
Le principe est :
● aller interroger la clé visites dans localStorage dès le chargement du document
● effectuer toutes les vérifications nécessaires (est-ce qu'il y a déjà quelque chose stocké à cet
emplacement, peut-on convertir cette chaîne de texte en nombre entier)
● incrémenter le compteur
● le stocker à nouveau au même emplacement pour le conserver
● afficher la valeur à un emplacement dans la page
<script>
if(typeof localStorage!='undefined') {
// Récupération de la valeur dans web storage
var nbvisites = localStorage.getItem('visites');
// Vérification de la présence du compteur
if(nbvisites!=null) {
// Si oui, on convertit en nombre entier la chaîne de texte qui fut stockée
nbvisites = parseInt(nbvisites);
} else {
nbvisites = 1;
}
// Incrémentation
nbvisites++;
Exemple n° 2 :
Web storage
116. // Stockage à nouveau en attendant la prochaine visite...
localStorage.setItem('visites',nbvisites);
// Affichage dans la page
document.getElementById('visites').innerHTML = nbvisites;
} else {
alert("localStorage n'est pas supporté");
}
</script>
Pour l'affichage, cet exemple se sert de l'identifiant id et de la fonction getElementById() pour le cibler, afin
d'accéder à sa propriété innerHTML, c'est-à-dire son contenu HTML interne, modifiable.
Attention : cette information restera spécifique et locale au visiteur, ne sera pas échangée avec le serveur
(hors utilisation d'Ajax par exemple), et donc ne pourra être exploitée pour établir des statistiques
générales.
Web storage
117. Web storage
Utilisation de JSON :
Web Storage est bien pratique pour stocker de simples chaînes de texte. Lorsqu'il s'agit de manipuler des données
plus complexes, entre autres des objets JavaScript, il faut leslinéariser au préalable en chaînes de texte puisque
Web Storage n'accepte que ce type de données.
Le format JSON (JavaScript Object Notation) est la solution de prédilection. Deux méthodes équipent les
navigateurs modernes : JSON.stringify() qui prend en paramètre un objet et renvoie une chaîne de texte linéarisée,
et son inverse JSON.parse() qui reforme un objet à partir de la chaîne linéarisée.
Des frameworks populaires tels que jQuery sont équipés de fonctions similaires (parseJSON) pour les anciens
navigateurs qui ne seraient pas équipés en natifs de telles méthodes de conversion.
Stockage :
var monobjet =
{
propriete1 : "valeur1",
propriete2 : "valeur2"
};
var monobjet_json = JSON.stringify(monobjet);
sessionStorage.setItem("objet",monobjet_json);
Lecture :
var monobjet_json = sessionStorage.getItem("objet");
var monobjet = JSON.parse(monobjet_json);
// Affichage dans la console
console.log(monobjet);
Dans le cadre de la lisibilité de cette démonstration, cet exemple de code ne fait
appel que modestement à JSON, il serait possible de l'exploiter de façon beaucoup
plus complexe et évoluée en fonction de la quantité de données à stocker et de leur
provenance.
118. Aller plus loin :
L'API prévoit aussi des événements storage pour être notifié à chaque changement opéré dans l'espace
alloué. Ceux-ci ne sont pas encore très répandus.
Pour mettre en place des stockages plus évolués, pour des données binaires ou bien du point de vue de la
structure et des opérations de recherche, tri et maintenance, deux approches coexistent :
WebSQL dont la spécification est au point mort et qui ne sera pas maintenu à long terme ni intégré à
Firefox et Internet Explorer, mais qui a été implémenté par WebKit et Opera. Cette tentative faisait entrer le
langage SQL côté client, ce qui était compréhensible pour les développeurs utilisant déjà les bases côté
serveur (MySQL, etc) mais n'est pas conforme à l'esprit des différents standards du web : cela nécessiterait
de spécifier totalement SQL ou un sous-ensemble tel que SQLite ce qui n'est pas le rôle du W3C.
IndexedDB (Indexed Database) revêt une approche totalement orientée vers JavaScript, sans SQL,
avec de la manipulation d'objets. Elle est cependant encore peu répandue (IE10 avec préfixe, Chrome et
Firefox avec préfixe) ; et demande une phase d'apprentissage supplémentaire même pour les développeurs
déjà aguerris avec SQL.
Web storage
119. Prise en charge :
Pour les versions d'Internet Explorer antérieures à IE8, il existe une interface nommée userData qui alloue 1
Mo par domaine et qui fonctionne sensiblement de la même manière. Pour l'exploiter, il faudra cependant
adapter les fonctions au cas par cas, ou bien passer par un framework unifiant toutes les méthodes d'appel
en fonction du stockage disponible.
120. Web sockets
●
Liens :
– http://dev.opera.com/articles/view/web-storage/
– https://developers.google.com/web-toolkit/doc/latest/DevGuideHtm
– https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Storag
– http://msdn.microsoft.com/en-us/library/cc197062(VS.85).aspx#_d
– http://theburningmonk.com/2010/12/having-fun-with-html5-local-
– http://diveintohtml5.info/detect.html
122. Web sql
Ouverture d'une base de données :
html5rocks.webdb.db = null;
html5rocks.webdb.open = function()
{
var dbSize = 5 * 1024 * 1024; // 5MB
html5rocks.webdb.db = openDatabase("Todo", "1.0", "Todo manager", dbSize);
}
html5rocks.webdb.onError = function(tx, e)
{
console.log("There has been an error: " + e.message);
}
html5rocks.webdb.onSuccess = function(tx, r)
{
// re-render the data.
// loadTodoItems is defined in Step 4a
html5rocks.webdb.getAllTodoItems(loadTodoItems);
}
123. Web sql
Creation d'une table :
html5rocks.webdb.createTable = function()
{
// Récupération du handle de la database
var db = html5rocks.webdb.db;
db.transaction(function(tx)
{
tx.executeSql("CREATE TABLE IF NOT EXISTS " +
"todo(ID INTEGER PRIMARY KEY ASC, todo TEXT, added_on
DATETIME)", []);
});
}
124. Web sql
Ajout d'une donnée dans une table :
html5rocks.webdb.addTodo = function(todoText)
{
// Récupération du handle de la database
var db = html5rocks.webdb.db;
db.transaction(function(tx)
{
var addedOn = new Date();
tx.executeSql("INSERT INTO todo(todo, added_on) VALUES (?,?)",
[todoText, addedOn],
html5rocks.webdb.onSuccess,
html5rocks.webdb.onError);
});
}
125. Web sql
Sélection d'une donnée dans une table :
html5rocks.webdb.getAllTodoItems = function(renderFunc)
{
// Récupération du handle de la database
var db = html5rocks.webdb.db;
db.transaction(function(tx)
{
tx.executeSql("SELECT * FROM todo", [], renderFunc,
html5rocks.webdb.onError);
});
}
126. Web sql
Mise en forme des données issue de la base de données :
function loadTodoItems(tx, rs)
{
var rowOutput = "";
var todoItems = document.getElementById("todoItems");
for (var i=0; i < rs.rows.length; i++)
{
rowOutput += renderTodo(rs.rows.item(i));
}
todoItems.innerHTML = rowOutput;
}
function renderTodo(row)
{
return "<li>" + row.todo +
" [<a href='javascript:void(0);' onclick='html5rocks.webdb.deleteTodo(" +
row.ID +");'>Delete</a>]</li>";
}
127. Web sql
Suppression d'une données dans une table :
html5rocks.webdb.deleteTodo = function(id)
{
// Récupération du handle de la database
var db = html5rocks.webdb.db;
db.transaction(function(tx)
{
tx.executeSql("DELETE FROM todo WHERE ID=?", [id],
html5rocks.webdb.onSuccess,
html5rocks.webdb.onError);
});
}
128. Web sql
Initialisation :
....
function init()
{
html5rocks.webdb.open();
html5rocks.webdb.createTable();
html5rocks.webdb.getAllTodoItems(loadTodoItems);
}
</script>
<body onload="init();">
129. Web sql
●
Liens :
– http://www.w3.org/TR/webdatabase/
– http://www.w3.org/TR/IndexedDB/
– http://html5sql.com/index.html
131. Web worker
Vérification du support :
if(typeof(Worker)!=="undefined")
{
// Yes! Web worker support!
// Some code.....
}
else
{
// Sorry! No Web Worker support..
}
132. Web worker
Création d'un worker fichier « workers.js » :
var i=0;
function timedCount()
{
i=i+1;
postMessage(i);
setTimeout("timedCount()",500);
}
timedCount();
133. Web worker
Création d'un worker objet :
if (typeof(w)=="undefined")
{
w = new Worker("demo_workers.js");
}
Il est possible de déclarer un handle de messages associé au worker :
w.onmessage=function(event)
{
document.getElementById("result").innerHTML = event.data;
};
135. Exemple complet :
<!DOCTYPE html>
<html>
<body>
<p>Count numbers: <output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<br><br>
<script>
var w;
function startWorker()
{
If (typeof(Worker) !== "undefined")
{
if(typeof(w)=="undefined")
{
w = new Worker("demo_workers.js");
}
w.onmessage = function (event)
{
document.getElementById("result").innerHTML=event.data;
};
} else {
document.getElementById("result").innerHTML="Sorry, your browser does not support Web Workers...";
}
}
function stopWorker()
{
w.terminate();
}
</script>
</body>
</html>
136. Web worker
●
Liens :
– https://developer.mozilla.org/en-US/docs/Web/Guide/Performance
– http://www.siteduzero.com/informatique/tutoriels/html5-web-work
– http://blogs.msdn.com/b/davrous/archive/2011/07/08/introduction-
– http://www.w3schools.com/html/html5_webworkers.asp
–
138. App. offline
L’application cache repose principalement sur l’utilisation d’un fichier “manifest” à
ajouter aux pages HTML de votre site.
Tout d’abord, créons donc une structure basique de page web :
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#main{
width:900px;
margin:auto;
}
</style>
</head>
<body>
<div id="main">
<h1>Ceci est mon application offline</h1>
<img src="earth-folder.png" />
</div>
</body>
</html>
139. App. offline
Afin d’utiliser le cache d’application, il va falloir déclarer un fichier manifest.
Ce fichier se déclare dans la balise html comme ceci :
<html manifest="site.manifest">
Une fois déclaré, il faut bien sûr créer le fichier manifest en question. Appelons le nôtre
“site.manifest”.
Dans ce fichier, qui commence obligatoirement par la ligne “CACHE MANIFEST”,
nous allons déclarer les fichiers qui doivent être mis en cache :
CACHE MANIFEST
# Version 0.1
index.html
earth-folder.png
140. App. offline
On peut également y ajouter des commentaires. Chaque ligne de commentaire doit commencer par #. Il est important
de versionner son fichier manifest via un commentaire, afin que le navigateur détecte par la suite les changements
dans le fichier.
Notons qu’il est possible d’utiliser des URL absolues (http://www.mon-url.com/absolue/fichier.html).
Il est possible d’ajouter différentes sections à notre fichier manifest :
● CACHE, il s’agit de la section par défaut qui liste les fichiers à mettre en cache.
● NETWORK, qui liste les fichiers qui nécessitent obligatoirement une connexion
internet.
● FALLBACK, qui liste les fichiers qui, au cas où ils ne soient pas accessibles
en ligne, doivent renvoyer vers d’autres fichiers.
L’exemple suivant représente un site web classique dont la page d’accueil, le CSS et les images sont mises en cache.
Si l’utilisateur se connecte à la page d’accueil en étant hors ligne, la page offline.html lui est présentée au lieu
d’index.html. Il est donc informé qu’il est déconnecté. Par conséquent il ne pourra pas accéder aux autres pages
du site, puisque la section NETWORK spécifie via une étoile “*”, que tous les autres fichiers requièrent une connexion
internet.
CACHE MANIFEST
# v0.1
CACHE:
index.html
css/style.css
img/logo.png
FALLBACK:
/ /offline.html
NETWORK:
*
141. App. offline
Le .htaccess :
Nous arrivons maintenant au passage (un peu) délicat. Il va falloir déclarer le MIME-type du fichier manifest.
Ceci se fait par l’intermédiaire du fichier de configuration de serveur. Dans la grande majorité des cas vous utiliserez
un fichier .htaccess pour les projets PHP.
Créez donc un fichier .htaccess dans le répertoire de votre application et ajoutez-y simplement la ligne :
AddType text/cache-manifest manifest
Dans cette ligne, on déclare que tous les fichiers se terminant par “manifest” ont pour MIME-type
“text/cache-manifest”.
142. App. offline
Test de l’application hors ligne :
Afin de pouvoir tester localement notre application, nous allons devoir passer par Apache (et oui, faites chauffer vos WAMP
/ MAMP / LAMP !).
Plaçons notre application dans le dossier de votre serveur (www pour WAMP) et rendez-vous sur l’adresse http://localhost/
Si tout se passe bien, votre page s’affiche.
Maintenant stoppez les services de WAMP, puis rafraîchissez la page.
Alors qu’une page classique aurait naturellement fait afficher une belle erreur 404… Votre page est toujours là !
Ouvrez maintenant la console de votre navigateur si celui-ci en possède une (pour Chrome, elle se trouve dans Outils,
Outils de développement, onglet Console).
On peut y voir ceci :
Creating Application Cache with manifest http://localhost/le-chemin-vers-votre-manifest
Application Cache Checking event
Application Cache Downloading event
Application Cache Progress event (0 of 3)
... (1 of 3)
... (2 of 3)
... (3 of 3)
Application Cache Cached event
On y voit en effet tous les événements qui ont lieu lorsque votre navigateur met à jour son AppCache. Les plus coriaces
d’entre vous souhaiterons pouvoir intercepter ces événements pour pouvoir effectuer des traitements au moment du
déclenchement de ces événements.
Ces événements seront détaillés dans la partie “aller plus loin” de ce tutoriel.
143. App. offline
Mise à jour du manifest :
Attention soyez bien attentif à présent ! La phrase suivante a de quoi perturber : une fois votre application
dans l’AppCache grâce au fichier manifest, c’est cette version offline qui a la priorité sur la version en ligne !
Pourquoi ?
Tout simplement parce que vous lui avez justement dit de le stocker dans le cache ! C’est exactement comme
lorsque votre navigateur garde en mémoire une image ou un CSS sur un site, afin de ne pas avoir à le
télécharger à nouveau. Seulement, c’est un peu plus perturbant lorsqu’il est question d’un fichier HTML,
je le reconnais… Et donc, comment fait-on pour mettre à jour le cache avec la version en ligne ?
L’Application Cache sera mis à jour si :
● L’utilisateur vide son cache manuellement.
● Le fichier manifest change.
● Le cache est mis à jour avec du code Javascript.
Voilà pourquoi il était important d’insérer un numéro de version dans un commentaire ! Il suffit de changer
ce numéro de version pour obliger l’AppCache du client à se mettre à jour. Si vous effectuez peu de mises à
jour (dans le cas d’un site vitrine par exemple) c’est la meilleure solution. Par contre, si vous avez besoin
que le client soit en permanence à jour, on préfèrera la version Javascript. Et encore une fois, c’est dans la
section “Aller plus loin” que ça se passe !
144. App. offline
Aller plus loin avec le manifest :
La solution peut être de créer un service générant le manifest en changeant, d’une part, de version à chaque
nouvel article publié et, d’autre part, en listant les URLs des derniers articles dans le cache explicite. Le
chargement prendra plus de temps mais le lecteur pourra consulter l’article hors-ligne sans plus d’effort.
Attention, les pages implicites qui déclarent le manifest sans être listées dans ce dernier y sont ajoutées et
seront téléchargées elles aussi lors de la mise à jour du cache.
Soyez prudent quand vous activez le manifest et ne multipliez pas les pages. Dans le cas du blog par exemple
les pages affichant les articles ne doivent pas utiliser le manifest. Le lecteur ne souhaite certainement pas
télécharger l’ensemble des articles qu’il a déjà lu à chaque nouvel article.
Cette solution minimaliste peut convenir à certains, mais elle n’est pas applicable pour un site dont le contenu
change beaucoup ou pour un site à fort trafic tant l’utilisation du cache est mauvaise.
Pour optimiser l’utilisation du cache, il faut le considérer comme la vue statique de l’application qui évoluera au
gré des changements d’interface et non au gré du contenu. Le contenu dynamique devra être servi par des
requêtes asynchrones. Pour la mise en cache et le fonctionnement il faudra utiliser les nouvelles API
JavaSript : LocalStorage et document.onLine. De cette manière, le manifest redeviendra un fichier statique
évoluant au gré des versions de l’application.
Pour garantir l’indexation du contenu par les moteurs de recherche et assurer la compatibilité avec d’anciens
navigateurs, prévoyez toujours un mode dégradé sans manifest ni contenu asynchrone.
145. App. offline
Notes de sécurité :
Notez que le cache est maintenu par nom de domaine. Il n’existe qu’une seule instance du même manifest
pour un serveur. Pour les serveurs hébergeant plusieurs applications, l’utilisation d’hôte virtuel est plus que
conseillée.
Le cache ne doit jamais contenir de données confidentielles. Les pages de login et tous services de sécurité
doivent être exclus du cache. Ne les listez jamais dans le manifest sauf pour les exclure et surtout n’intégrez
pas le manifest dans ces pages.
Informez l’utilisateur sur les dangers de ce service et surtout laissez le choisir d’activer ou non le
fonctionnement hors ligne. En effet si le navigateur lui-même n’est pas protégé, toute personne y ayant
accès pourra consulter le cache. Pour limiter le problème vous pouvez activer le service en stockant un
cookie sur le navigateur si l’utilisateur active le mode hors ligne. Ainsi le lecteur devra répéter l’opération
pour tous les navigateurs sur lesquels il souhaite consulter le site.
En dehors de ces règles de sécurité basiques, toutes les règles de sécurité inhérentes aux sites web
s’appliquent.
146. App. offline
L’API Javascript HTML5 possède un objet window.applicationCache. Cet objet permet de :
● connaître les états du cache
● attacher des traitements aux événements
● faire une mise à jour du cache
● changer le cache actuel
Voici la classe ApplicationCache telle qu’elle est donnée par le WHATWG :
interface ApplicationCache
{
// update status
const unsigned short UNCACHED = 0;
const unsigned short IDLE = 1;
const unsigned short CHECKING = 2;
const unsigned short DOWNLOADING = 3;
const unsigned short UPDATEREADY = 4;
const unsigned short OBSOLETE = 5;
readonly attribute unsigned short status;
// updates
void update();
void swapCache();
// events
attribute Function onchecking;
attribute Function onerror;
attribute Function onnoupdate;
attribute Function ondownloading;
attribute Function onprogress;
attribute Function onupdateready;
attribute Function oncached;
attribute Function onobsolete;
};
ApplicationCache implements EventTarget;
147. App. offline
Ainsi on peut tester le statut actuel :
if (webappCache.status == window.applicationCache.UPDATEREADY)
Ou avec un switch :
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
…
Mais il est préférable de passer par la gestion d’événements pour détecter lorsque l’Application Cache change de statut :
var webappCache = window.applicationCache;
webappCache.addEventListener("updateready", updateCache, false);
webappCache.update();
function updateCache()
{
webappCache.swapCache();
alert("Une nouvelle version est disponible.nVeuillez rafraîchir la page pour mettre à jour.");
}
148. App. offline
● La méthode update() force le lancement du processus de mise à jour du cache.
● addEventListener(“updateready”, updateCache, false) lancera la fonction updateCache dès que le
statut de l’AppCache passera en “updateready”.
● swapCache() permet d’échanger l’ancien cache avec le nouveau cache, ce qui finalise l’opération.
Si vous souhaitez trouver de plus amples informations sur le sujet, je vous invite à vous rendre sur la
page Application Cache du WHATWG, où sont listés tous les status que peut prendre
applicationcache.status, et tous les événements associés.
Dernière petite remarque, il est possible de tester si l’utilisateur est connecté à internet ou non avec la
propriété :
navigator.onLine
Et voilà ! Vous avez tous les outils en main pour réaliser de superbes applications web ! Il y a fort à
parier que ces applications deviendront le standard sur les smartphones d’ici quelques années,
puisqu’elles fonctionnent aussi bien sur iPhone qu’Android.
Couplé avec une balise canvas, on pourra par exemple jouer à des jeux vidéos en 3D dans le
navigateur, qui seront compatibles avec tous les mobiles ! Pas besoin de s’embêter à développer
plusieurs versions pour chaque OS mobile, du HTML/CSS et Javascript suffisent !
149. App. offline
Voici le code source de la page en question :
<!DOCTYPE html>
<html manifest="site.manifest">
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-
scale=1.0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="earth-folder.png">
<link rel="apple-touch-icon-precomposed" href="earth-folder.png">
<link rel="apple-touch-startup-image" href="earth-folder.png" />
<style type="text/css">
#main{
width:900px;
margin:auto;
}
</style>
</head>
<body>
<div id="main">
<h1>Cette page est accessible hors ligne</h1>
<p>Elle possède une icone d'application pour les smartphones.</p>
<img src="earth-folder.png" />
</div>
</body>
</html>
150. App. offline
Le fichier site.manifest :
CACHE MANIFEST
# Version 0.4
exemple-application-cache-manifest-html5.html
earth-folder.png
Le .htaccess :
AddType text/cache-manifest manifest
155. jQuery
● La naissance de JavaScript :
● 1995 : Brendan Eich développe pour Netscape Communications
Corporation, un langage de script, appelé Mocha, puis LiveScript et
finalement JavaScript
● Javascript est intégré dans le navigateur Netscape 2. Succès immédiat.
● Javascript n'est pas java !! D'un point de vue des propriétés, Javascript est
plus proche du langage python que du java.
● La guerre des navigateurs :
● Netscape et Microsoft (avec JScript dans Internet Explorer) ont développé
leur propre variante de JavaScript avec des fonctionnalités supplémentaires
et incompatibles, notamment dans la manipulation du DOM (modèle objet
du navigateur WEB)
● 1997 : Adoption du standard ECMAScript.
Les spécifications sont rédigées dans le document Standard ECMA-262.
156. jQuery
Définition de jQuery :
● Une bibliothèque javascript open-source et cross-browser
● Elle permet de traverser et manipuler très facilement l'arbre DOM des pages web à l'aide
d'une syntaxe fortement similaire à celle d'XPath.
● JQuery permet par exemple de changer/ajouter une classe CSS, créer des animations,
modifier des attributs, etc.
● Gérer les événements javascript
● Faire des requêtes AJAX simplement
157. jQuery
Ce que jQuery n’est pas :
● Un substitut pour apprendre JavaScript
● jQuery est très puissant et très pratique, mais vous devez néanmoins
connaitre les bases de Javascript, notamment la partie “objet” du langage.
● Voir des livres comme :
“Object Oriented Javascript de Stoyan Stefanov” ou
“jQuery, novice to ninja” (google est votre ami)
● Une réponse à tout
● Utilisez jQuery uniquement lorsque c’est nécessaire. On commence toujours
par HTML+CSS avant de chercher des plugins jQuery magiques.
● De nombreuses UI sont pures html+CSS
158. jQuery
Une simple bibliothèque à importer :
Disponible sur le site de Jquery : http://jquery.com/
<script type="text/javascript" src="jquery.js"></script>
Ou directement sur Google code :
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min
.js">
</script>
159. jQuery
La fonction jQuery() :
● jQuery repose sur une seule fonction : jQuery() ou $()
● C’est une fonction JavaScript
● Elle accepte des paramètres
● Elle retourne un objet
● $ : Syntaxe issue de « Prototype »