Exercices TP-2

  1. Bienvenue au TP-2
  2. Révisions
    1. Révision : liste jQuery
    2. Décomposition d'une ligne jQuery
    3. Révision : style
    4. Révisions: éléments affectés
    5. Révision : création élément avec jQuery
    6. Révisons: ajouter élément dans DOM avec jQuery
  3. JavaScript : notions de base
    1. Les variables
    2. Portée des variables : global
    3. Portée des variables : global
    4. Portée des variables : locale
    5. Portée des variables : local
    6. Les fonctions
    7. Les fonctions sont des objets
    8. Fonctions et appel
    9. Fonctions : appel click
  4. Rappel : expressions rationnelles
    1. Expression rationnelle simple
    2. Début
    3. Fin
    4. Début et fin
    5. crochets
    6. Répétition
    7. Expression simple : [ ]
    8. Expression simple : +
    9. Expression simple : []+
    10. Expression simple : *
    11. Expression simple : .
    12. Expression simple : [-]
    13. Uniquement des chiffres
    14. Uniquement des lettres
    15. Adresse mail - 1
    16. Adresse mail - 1: correction
    17. Adresse mail - 2
    18. Adresse mail - 2 : correction
    19. Négation classe de caractères
  5. Exo-1 : formulaire & String
    1. String
    2. Exo-1 : Login simplifié
    3. Correction
    4. Exo-1 : formulaire complet
    5. Correction
    6. Exo-1 : mot de passe et confirmation
    7. Correction
  6. Exo-1 : champs email
    1. Correction :
    2. event.preventDefault()
    3. Envoi du formulaire
    4. Envoi du formulaire, suite
    5. Envoi du formulaire: AAA
    6. Envoi du formulaire: CCC
    7. Envoi du formulaire: CCC
    8. Envoi du formulaire: DDD
    9. Envoi du formulaire: EEE
    10. Envoi du formulaire: fin
    11. Correction
  7. Rappels : sélecteurs CSS
    1. Rappel : arbre des éléments HTML
    2. Sélecteur de descendants
    3. Descendants - 1
    4. Descendants - 2
    5. Descendants
    6. Descendants
    7. Descendants
    8. Descendants
    9. Descendants directs
    10. Descendants directs
    11. Descendants directs
  8. Compositions de sélecteurs
    1. Composition
    2. Composition
    3. Composition
    4. Composition
    5. Composition
    6. Composition
  9. Priorité des sélecteurs
    1. Priorité des sélecteurs
    2. Priorités CSS : exercice
    3. Priorités CSS : exercice
    4. Priorités CSS : exercice
    5. Priorités CSS : exercice
  10. Onglets
  11. Onglets : HTML/CSS
    1. Onglets CSS 1
    2. Correction
    3. Onglets CSS 2
    4. Correction
    5. Onglets complets
    6. Onglets: arbre
    7. Onglets contenu : CSS
    8. Onglets contenu : CSS fin
    9. Correction : fin onglets.css
  12. Onglets : JS
    1. Gestionnaire d'événements
    2. Liste jQuery
    3. Gestionnaires d'événements multiple
    4. Rappel : fonctions jQuery : class
    5. Rappel : event / this
    6. Onglets JS : menu
    7. Correction
    8. Manipulation liste
    9. Liste des onglets
    10. Indice de l'onglet cliqué
    11. Correction
    12. Onglets : fin
    13. Correction
  13. Jeu : morpion
    1. Correction
    2. Fermetures
    3. Correction

1. Bienvenue au TP-2

1.1 Bienvenue au TP-2

Pour votre progression, c'est très important de finir le TP précédent avant de commencer celui-ci.

2. Révisions

2.1 Révisions

Commençons ce TP par une rapide révision des notions du TP précédent.

Révisions

2.2 Révision : liste jQuery

HTML:

	<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>

JS:

XYZ.css('color','red');

Que faut-il écrire à la place de XYZ pour afficher tous les textes "bla bla bla" en rouge ?

Révisions

2.3 Décomposition d'une ligne jQuery

Décomposons la ligne suivante en plusieurs parties:

$('p').css('color','red');


Révisions

2.4 Révision : style

HTML:

	<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>

CSS:

.important
{
color: red;
}

JS:

$('p').XYZ;
On a vu, au premier cours, qu'on pouvait, avec une fonction jQuery, ajouter une classe à un élément.
Que faut-il écrire à la place de XYZ pour afficher tous les textes "bla bla bla" en rouge (en s'appuyant cette fois sur le fichier CSS) ?

Révisions

2.5 Révisions: éléments affectés

HTML:

	<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>

CSS:

.important
{
color: red;
}

Combien d'éléments HTML ont class="important" après l'exécution du JS suivant :

$('p').addClass('important');

Révisions

2.6 Révision : création élément avec jQuery

HTML:

	<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>

JS:

var el=XXX;
$('body').YYY(el);

On veut ajouter un 4e paragraphe.

Que faut-il écrire à la place de XXX ?

(en cas de difficulté: cours)

Révisions

2.7 Révisons: ajouter élément dans DOM avec jQuery

HTML:

	<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>

JS:

var el=$('<p></p>');
$('body').YYY(el);

On veut ajouter un 4e paragraphe.

Que faut-il écrire à la place de YYY ?

3. JavaScript : notions de base

3.1 JavaScript : notions de base

Au premier TP on a écrit des petits programmes en JavaScript simples.

Pour aller plus loin, on a besoin de voir les notions de base de la syntaxe et de l'utilisation du JavaScript.

JavaScript : notions de base

3.2 Les variables

Pour déclarer une variable on utilise généralement "var".

Ouvrez la console des outils de dév.
Tapez : "var x=123;" (suivi d'entrée)
Puis tapez juste  "x" (suivi d'entrée)
Vous avez crée une variable appelée "x".
Elle contient une valeur (123) de type "number".

Typage dynamique :

Maintenant, tapez x="bonjour";
"x" contient maintenant une chaîne de caractères (string).
Le changement entre nombre et string s'est fait automatiquement. C'est ce qu'on appelle le "typage dynamique".

(ça ressemble beaucoup au PHP)



JavaScript : notions de base

3.3 Portée des variables : global

C'est important de comprendre où on peut utiliser les variables.
Commençons par la portée (scope) globale:

var a =1;
console.log(a);
exemple_1();
console.log(a);

function exemple_1()
{

a=2;
}

"a" est définie en dehors de toute fonction. Elle est donc globale (comme en PHP).

On peut donc l'utiliser directement dans la fonction exemple_1 (En PHP, il faudrait utiliser "global").

La variable "a" dans exemple_1() est la même que la variable "a" à l'extérieur.

JavaScript : notions de base

3.4 Portée des variables : global

var a =1;
console.log(a);
exemple_1();
console.log(a);

function exemple_1()
{

a=2;
}

Qu'affiche ce programme ?


JavaScript : notions de base

3.5 Portée des variables : locale

On peut définir une variable dans une fonction.
Elle a une portée (scope) locale.

Dans cet exemple il y a deux variables "a" différentes :


var a =1;
console.log(a);
exemple_1();
console.log(a);
exemple_2();
console.log(a);

function exemple_1()
{

a=2;
}

function exemple_2()
{

var a=3;
}

JavaScript : notions de base

3.6 Portée des variables : local

var a =1;
console.log(a);
exemple_1();
console.log(a);
exemple_2();
console.log(a);

function exemple_1()
{

a=2;
}

function exemple_2()
{

var a=3;
}

Qu'affiche ce programme ?

JavaScript : notions de base

3.7 Les fonctions

En JavaScript les fonctions peuvent être définies à l'intérieur d'autres fonctions.
C'est très utilisé.

La portée est la même que pour variables locales:

function exemple_1()
{
// ici on peut appeler exemple_2();
exemple_2();
// Par contre, exemple_3() n'est pas accessible d'ici.

function exemple_2()
{
// ici on peut appeler exemple_3();
exemple_3();

function exemple_3()
{

}
}
}


JavaScript : notions de base

3.8 Les fonctions sont des objets

En JavaScript les fonctions sont des objets. Elles peuvent être mises dans des variables et manipulées comme n'importe quel objet dans une variable.

C'est une différence importante avec d'autres langages (Java, C...).

// Exemple avec une fonction déclarée séparément
var a=exemple_1;
a();

function exemple_1()
{
console.log('Bonjour');
}

// Exemple avec une fonction anonyme
var b=function()
{
console.log("Au-revoir");
};

b();

Une fonction étant un objet, on peut la passer en argument à une autre fonction.

C'est ce qu'on a fait souvent au TP-1 avec jQuery:

	$('img').mousemove(function(event)
{
$('#affiche-x').text(event.pageX);
$('#affiche-y').text(event.pageY);
}
);
On crée une fonction anonyme (function(event){...}) et on la passe directement en argument à la fonction .mousemove()

Il faut s'y habituer... c'est vraiment très utilisé en JavaScript.

JavaScript : notions de base

3.9 Fonctions et appel


function abc()
{
return 123;
}

var z=function()
{
return 456;
}

Dans chacun de ces exemples, que contient la variable "a" ?

JavaScript : notions de base

3.10 Fonctions : appel click

function abc()
{
return true;
}

Dans les exemples suivants, quel argument reçoit la fonction "click" ?


4. Rappel : expressions rationnelles

4.1 Rappel : expressions rationnelles

Une des tâches fréquentes en JS est de vérifier que les utilisateurs ont bien saisi les champs d'un formulaire.

Sécurité: La vérification en JS permet d'afficher immédiatement un message d'erreur, sans passer par le serveur, elle est donc très agréable pour l'utilisateur. Néanmoins, la validation devra aussi être faite impérativement coté serveur. Il est très facile pour un utilisateur mal-intentionné de contourner la validation coté client (JS).

Validation & expressions rationnelles
Par exemple, si on a demandé un nombre, il faut vérifier qu'il n'a pas rentré de lettres.
Si on a demandé une adresse mail, il faut vérifier que la saisie ressemble bien à une adresse mail.

Pour ca on va utiliser des expressions rationnelles.
Vous avez vu en cours de système les expressions rationnelles.

N'hésitez pas à relire quelques rappels sur le web.
Par exemple:
http://fr.wikipedia.org/wiki/Expression_rationnelle

Rappel : expressions rationnelles

4.2 Expression rationnelle simple

ici, on utilise l'expression rationnelle /^abc$/
Qui veut dire:
^ : commencer au début de la chaîne saisie
a: suivi de la lettre "a"
b: suivi de la lettre "b"
c: suivi de la lettre "c"
$: suivi de la fin de la chaîne saisie

Donc dans ce cas on impose que l'utilisateur ait saisi la chaîné "abc".


Rappel : expressions rationnelles

4.3 Début

Quelles saisies fonctionnent pour

/^a/ 

Rappel : expressions rationnelles

4.4 Fin

Quelles saisies fonctionnent pour

/a$/ 

Rappel : expressions rationnelles

4.5 Début et fin

Quelles expressions fonctionnent ?

Rappel : expressions rationnelles

4.6 crochets

Les crochets représentent un seul caractère parmi plusieurs.
Le tiret peut-être utilisé pour représenter une gamme de caractères.

Par exemple :
[ab] veut dire "soit a, soit b"
[abcd] veut dire "soit a, soit b, soit c, soit d".
[a-d] veut dire la même chose que [abcd] "soit a, soit b, soit c, soit d".
[0-9]  veut dire la même chose que [0123456789], c'est à dire "un chiffre"
[a-z] veut dire "une lettre minuscule"

Quelles saisies fonctionnent pour

/^a[bcd]e$/ 


Rappel : expressions rationnelles

4.7 Répétition

Le "+" et le "*" permettent d'indiquer une répétition de l'expression qui précède.

Par exemple:

a+ veut dire "une ou plus lettres a", exemples: "a", "aaaaa", "aaaaaa"
abc+ veut dire "a, suivi de b, suivi de une ou plus fois c". exemples: "abc", "abcc", "abcccccccc"

a* veut dire "zéro ou plus lettres a", exemples: "" (vide), "a", "aaaaaa"
abc* veut dire "a, suivi de b, suivi de zéro ou plus fois c". exemples: "ab", "abc", "abcccccccc"

[ab]+  comme si on répétait l'expression [ab] un nombre de fois [ab][ab][ab]... : exemple "baababbbabbabba"


Quelles saisies fonctionnent pour

/^ab+c$/ 


Rappel : expressions rationnelles

4.8 Expression simple : [ ]

Quelles saisies fonctionnent pour

/^x[rst]y$/ 

Rappel : expressions rationnelles

4.9 Expression simple : +

Quelles saisies fonctionnent pour

/^xy+z$/ 

Rappel : expressions rationnelles

4.10 Expression simple : []+

Quelles saisies fonctionnent pour

/^x[ab]+y$/ 

Rappel : expressions rationnelles

4.11 Expression simple : *

Quelles saisies fonctionnent pour

/^xy*z$/ 

Rappel : expressions rationnelles

4.12 Expression simple : .

Le "." représente n'importe quel caractère (un seul)

Quelles saisies fonctionnent pour

/^x.y$/ 

Rappel : expressions rationnelles

4.13 Expression simple : [-]

Quelles saisies fonctionnent pour

/^x[a-e]z$/ 

Rappel : expressions rationnelles

4.14 Uniquement des chiffres

Quelques exemples:

/^ab[cd]$/ : la lettre "a" puis la lettre "b" puis la lettre "c" OU la lettre "d" (donc abc ou abd sont ok.)

/^ab*$/ : la lettre "a" puis la lettre "b" répétée zero ou plusieurs fois (donc a ab abbb abbbbb sont ok.)

/^ab+$/ : la lettre "a" puis la lettre "b" répétée une ou plusieurs fois (donc ab abbb abbbbb sont ok.)

/^ab[a-z]$/ : la lettre "a" puis la lettre "b" puis n'importe quelle lettre (de "a" à "z")

/^ab[0-9]$/ : la lettre "a" puis la lettre "b" puis n'importe quel chiffre (de 0 à 9)

Maintenant, c'est à vous:
Quelle expression rationnelle si on veut une saisie uniquement composée de chiffres (au moins un chiffre) ?



Rappel : expressions rationnelles

4.15 Uniquement des lettres

Quelle expression rationnelle si on veut une saisie uniquement composée de lettres minuscules (au moins une lettre) ?

Rappel : expressions rationnelles

4.16 Adresse mail - 1

Quelle expression rationnelle si on veut une saisie composée d'au moins une lettre minuscule, suivie d'un arobase, suivi d'au moins une lettre minuscule ?

Rappel : expressions rationnelles

4.17 Adresse mail - 1: correction


correction

/^[a-z]+@[a-z]+$/


Rappel : expressions rationnelles

4.18 Adresse mail - 2

Adresse mail:

On veut valider des adresses mail simples.

Quelle expression rationnelle si on veut une saisie composée de
(remarque: le point à un sens particulier dans les expressions rationnelles, il faut donc l'échapper: \.)

Rappel : expressions rationnelles

4.19 Adresse mail - 2 : correction

Correction:

/^[a-z]+@[a-z]+\.[a-z]+$/.test('aqsdfsdf')

Voila!

Nous avons une expression rationnelle qui nous permet de vérifier des adresses mails simples.

Une expression plus complète
La validation d'une adresse mail correspondant aux normes RFC 822, RFC 5322 est très très compliquée, mais en pratique, on peut simplifier.
Un site de référence en la matière conseille :
/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i
le /i à la fin est l'option pour ignore la case (minuscule / majuscules)

Essayez de taper dans la console des outils de dév.:

/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test("aaa@bbb.ccc")

ou

/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test("aaabbb.ccc")


Rappel : expressions rationnelles

4.20 Négation classe de caractères

Une dernière expression:

[^abcd]

Qui veut dire « tout caractère SAUF a, b, c ou d. »

Attention à ne pas confondre avec le "^" en dehors de crochets, qui veut dire « le début de la chaîne ».

Un autre exemple:

[^a-z]

Qui veut dire « Tout caractère sauf une lettre. »


Un autre exemple :
si on veut trouver quelque-chose qui ressemble à une balise : <div class="xyz">

On peut écrire :

<[^>]+>

Çà se lit "<" suivi d'un n'importe quel caractère qui ne soit pas ">", ceci au moins une fois, suivi de ">".


à vous:


On veut identifier une expression des chaînes du type
nom="Toto"
prenom="Jo"
adresse="123 rue grande, Trifouilli"

C'est à dire : une suite de lettres minuscules, suivie d'un égal suivi d'un guillemet, suivi de caractères qui ne sont pas des guillemets, suivi d'un guillemet.

Écrivez l'expression entière : /^...$/


5. Exo-1 : formulaire & String

5.1 Exo-1 : formulaire & String

Reprenons l'exercice de la fin du TP-1, on va le renommer exo-1:

exo-1.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST">
<p><label>Nom : <input id="nom" name="nom" type="text"/></label><span id="erreur-nom">Non valide !</span></p>
<p><label>Login : <input id="login" name="login" type="text"/></label></p>
</form>
</body>
</html>

CSS:

#erreur-nom
{
color: red;
margin-left: 1em;
display: none;
}

JS:

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");

$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée");
var texte=$("#nom").val();
if(/[^a-zA-Z '-]/.test(texte))
{
$('#erreur-nom').show();
}
else
{
$('#erreur-nom').hide();
}
texte=texte.toLowerCase();
$('#login').val(texte);
});
console.log("La mise en place est finie. En attente d'événements...");
});

Vérifiez que tout marche bien.

Exo-1 : formulaire & String

5.2 String

On a besoin de manipuler des chaînes de caractères (String).

Les fonctionnalités les plus utiles :

Retrouvez la documentation ici.

Essayons :

Dans la console tapez :

var a="bonjour"

Ensuite tapez:

a.length

Ensuite tapez :

a=a+" c'est moi"
a.replace(/o/,"X")

Attention, le résultat du remplacement est affiché, mais "a" n'a pas été modifié (pour ca : a=a.replace(/o/,"X") )

/xyz/ est une expression rationnelle
Par défaut le remplacement ne se fait que sur la première occurrence de "o" trouvée:
"bonjour c'est moi" => "bXnjour c'est moi"
On peut spécifier l'option "g" à la fin de l'expression pour remplacer toutes les occurrences:

a.replace(/o/g,"X")
"bonjour c'est moi" => "bXnjXur c'est mXi"

Pour vérifier si une chaîne correspond à une expression on utilise test():
Tapez :

/b.*jour/.test("bonjour")

Rappel: /b.*jour/ se lit :

"b" suivi de n'importe quelle lettre (.) répétée zéro ou plus fois (*) suivi de "j", suivi de "o" suivi de "u", suivi de "r"

Essayez ensuite :

/b.*jour/.test("aurevoir")



Exo-1 : formulaire & String

5.3 Exo-1 : Login simplifié

On veut que le "Login" proposé soit une version simplifié du "Nom".

Faites en sorte que lorsque l'utilisateur tape dans le champs Nom, tous les caractères (sauf les lettres) soient remplacés par un tiret "-".

Exemple (l'espace a été remplacé par un tiret)



Exo-1 : formulaire & String

5.4 Correction


			...
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
...




Exo-1 : formulaire & String

5.5 Exo-1 : formulaire complet



En vous inspirant de la ligne   Nom, complétez le HTML du formulaire pour obtenir l'affichage de la figure.

(Faites uniquement le HTML, on verra le JS après).

Indications :




Exo-1 : formulaire & String

5.6 Correction


exo-1.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST">
<p>
<label>
Nom :
<input id="nom" name="nom" type="text"/>
</label>
<span id="erreur-nom" class="erreur">Non valide !</span>
</p>
<p>
<label>
Login :
<input id="login" name="login" type="text"/>
</label>
</p>
<p>
<label>
Mot de passe :
<input id="mdp" name="mdp" type="password"/>
</label>
<span id="erreur-mdp" class="erreur">Trop court !</span>
</p>
<p>
<label>
Confirmation :
<input id="confirm" name="confirm" type="password"/>
</label>
<span id="erreur-confirm" class="erreur">Différents !</span>
</p>
<p>
<input id="bouton" type="submit" value="Envoyer" />
</p>
</form>
</body>
</html>

Exo-1 : formulaire & String

5.7 Exo-1 : mot de passe et confirmation


Maintenant, passons au JavaScript.

On veut que le mot de passe fasse au moins 6 caractères.
On veut afficher une erreur si le mot de passe et la confirmation sont différents.

Indications :

Exemple de toggle :

if ( AAA ) { BBB.show(); } else { BBB.hide(); }
Peut s'écrire plus simplement :

BBB.toggle(AAA);

C'est à vous !

Exo-1 : formulaire & String

5.8 Correction

exo-1.js :

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");

$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée dans nom");
var texte=$("#nom").val();
$('#erreur-nom').toggle(/[^a-zA-Z '-]/.test(texte));
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
});

$('#mdp').keyup(function(event)
{
console.log("Une touche a été appuyée dans mdp");
var mdp=$('#mdp').val();
$('#erreur-mdp').toggle(mdp.length<6);
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('#confirm').keyup(function(event)
{
console.log("Une touche a été appuyée dans confirm");
var mdp=$('#mdp').val();
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});

console.log("La mise en place est finie. En attente d'événements...");
});

6. Exo-1 : champs email

6.1 Exo-1 : champs email


On veut ajouter un champs "Email" au formulaire et afficher un message d'erreur si l'adresse mail saisie ne correspond pas à une expression rationnelle.

Complétez le HTML et le JS pour obtenir le résultat décrit par la figure.



Exo-1 : champs email

6.2 Correction :

Important  : pour les exercices suivants, utilisez ce HTML  ou bien vérifiez que vos messages d'erreur ont bien class="erreur", exemple: <span id="erreur-nom" class="erreur">

exo-1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST">
<p>
<label>
Nom :
<input id="nom" name="nom" type="text"/>
</label>
<span id="erreur-nom" class="erreur">Non valide !</span>
</p>
<p>
<label>
Login :
<input id="login" name="login" type="text"/>
</label>
</p>
<p>
<label>
Email :
<input id="email" name="email" type="text"/>
</label>
<span id="erreur-email" class="erreur">Non valide !</span>
</p>
<p>
<label>
Mot de passe :
<input id="mdp" name="mdp" type="password"/>
</label>
<span id="erreur-mdp" class="erreur">Trop court !</span>
</p>
<p>
<label>
Confirmation :
<input id="confirm" name="confirm" type="password"/>
</label>
<span id="erreur-confirm" class="erreur">Différents !</span>
</p>
<p>
<input id="bouton" type="submit" value="Envoyer" />
</p>
</form>
</body>
</html>

exo-1.js

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");

$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée dans nom");
var texte=$("#nom").val();
$('#erreur-nom').toggle(/[^a-zA-Z '-]/.test(texte));
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
});

$('#email').keyup(function(event)
{
console.log("Une touche a été appuyée dans email");
var email=$('#email').val();
var emailEstOk=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i.test(email);
$('#erreur-email').toggle(emailEstOk===false);
});

$('#mdp').keyup(function(event)
{
console.log("Une touche a été appuyée dans mdp");
var mdp=$('#mdp').val();
$('#erreur-mdp').toggle(mdp.length<6);
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('#confirm').keyup(function(event)
{
console.log("Une touche a été appuyée dans confirm");
var mdp=$('#mdp').val();
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});


console.log("La mise en place est finie. En attente d'événements...");
});

Exo-1 : champs email

6.3 event.preventDefault()


Les actions de l'utilisateur sont gérées par des événements.

L'action par défaut de certains de ces événements peut être annulée avec la fonction event.preventDefault()

Voyons un exemple:

<a href="http://exemple.org">un lien</a>


$('a').click(function(event)
{
event.preventDefault();
});

L'action par défaut quand on clique sur un lien c'est de "suivre ce lien" (changer de page...).

En appelant .preventDefault(), cette action est annulée: rien ne se passe quand on clique sur le lien.

Quelques exemples d'actions pouvant être annulées:


Exo-1 : champs email

6.4 Envoi du formulaire

Pour l'instant notre formulaire ne fait rien lorsqu'on appuie sur le bouton "Envoyer".

Ajoutez une "action" au formulaire.

        <form method="POST">  =>    <form method="POST" action="traitement.html">

Créez un fichier traitement.html avec à l'intérieur, juste une phrase. Par exemple "Formulaire en cours de traitement".

(En pratique, on créerait, par exemple, un fichier php pour traiter réellement le formulaire)

Rafraîchissez la page et vérifiez que lorsque vous appuyez sur "Envoyer", vous êtes bien envoyé sur traitement.html


Exo-1 : champs email

6.5 Envoi du formulaire, suite

On veut bloquer l'envoi du formulaire s'il y a une erreur affichée.

Il nous faut donc:

AAA+BBB) réagir à l'événement "submit" du formulaire

   Attention: l'utilisateur pourrait soumettre le formulaire sans appuyer sur le bouton. Par exemple, il pourrait  appuyer sur la touche "entrée" dans un champs texte. C'est pourquoi il existe un événement spécial appelé "submit" et qui est envoyé au <form>. Il est donc préférable d'utiliser celui-ci que d'utiliser l'événement "click" sur le bouton <input>.

CCC) vérifier si un message d'erreur est affiché

DDD) si c'est le cas bloquer / annuler l'événement

EEE) afficher un avertissement


	$('AAA').BBB(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});

On va voir ensemble, dans les pages suivantes, ces points.

Important  : vérifiez que les messages d'erreur de votre formulaire ont bien class="erreur", exemple: <span id="erreur-nom" class="erreur">

Exo-1 : champs email

6.6 Envoi du formulaire: AAA

AAA+BBB) réagir à l'événement "submit" du formulaire

CCC) vérifier si un message d'erreur est affiché

DDD) si c'est le cas bloquer / annuler l'événement

EEE) afficher un avertissement


	$('AAA').BBB(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});

On veut réagir à l'événement "submit" généré par le formulaire (pas par le bouton).

Que faut-il écrire à la place de AAA ?

Exo-1 : champs email

6.7 Envoi du formulaire: CCC

AAA+BBB) réagir à l'événement "submit" du formulaire

CCC) vérifier si un message d'erreur est affiché

DDD) si c'est le cas bloquer / annuler l'événement

EEE) afficher un avertissement


	$('form').submit(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});

On voudrait maintenant savoir s'il y a un message d'erreur affiché.
On va donc
1) construire une liste jQuery contenant tous les messages d'erreur qui sont affichés
2) voir si la longueur de cette liste (.length) est différente de 0

Commençons par 1)
Regardez tous les messages d'erreur dans le fichier HTML.
Que faudrait-il écrire pour obtenir la liste jQuery de tous les messages d'erreur ?
(on ne s'occupe pas encore de savoir s'ils sont affichés ou pas)
Essayez dans la console avant de répondre


Exo-1 : champs email

6.8 Envoi du formulaire: CCC

CCC) vérifier si un message d'erreur est affiché


DDD) si c'est le cas bloquer / annuler l'événement

EEE) afficher un avertissement


	$('form').submit(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});

On voudrait maintenant savoir s'il y a un message d'erreur affiché.
On va donc
1) construire une liste jQuery contenant tous les messages d'erreur qui sont affichés
2) voir si la longueur de cette liste (.length) est différente de 0

$('.erreur') est la liste de tous les messages d'erreur. Pour conserver uniquement ceux qui sont affichés on peut utiliser la pseudo-class :visible

Ce qui donne
$('.erreur:visible')

Il ne nous reste plus qu'à vérifier si cette liste à une longueur différente de zéro.
Que faut-il écrire à la place de CCC ?

Exo-1 : champs email

6.9 Envoi du formulaire: DDD

DDD) si c'est le cas bloquer / annuler l'événement

EEE) afficher un avertissement


	$('form').submit(function(event)
{
if($('.erreur:visible').length!==0)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});

On a vu il y a quelques pages comment bloquer (annuler) un événement.
Que faut-il écrire à la place de DDD ?

Exo-1 : champs email

6.10 Envoi du formulaire: EEE

EEE) afficher un avertissement


	$('form').submit(function(event)
{
if($('.erreur:visible').length!==0)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});


On veut afficher un avertissement : une petite fenêtre avec un message.
On l'a fait au début du TP-1...
Que faut-il écrire à la place de EEE ?

Exo-1 : champs email

6.11 Envoi du formulaire: fin

Vérifiez que tout marche bien.

N'oubliez pas de recharger la page du formulaire après avoir fait des modifications.

Exo-1 : champs email

6.12 Correction

exo-1.html :

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST" action="traitement.html">
<p>
<label>
Nom :
<input id="nom" name="nom" type="text"/>
</label>
<span id="erreur-nom" class="erreur">Non valide !</span>
</p>
<p>
<label>
Login :
<input id="login" name="login" type="text"/>
</label>
</p>
<p>
<label>
Email :
<input id="email" name="email" type="text"/>
</label>
<span id="erreur-email" class="erreur">Non valide !</span>
</p>
<p>
<label>
Mot de passe :
<input id="mdp" name="mdp" type="password"/>
</label>
<span id="erreur-mdp" class="erreur">Trop court !</span>
</p>
<p>
<label>
Confirmation :
<input id="confirm" name="confirm" type="password"/>
</label>
<span id="erreur-confirm" class="erreur">Différents !</span>
</p>
<p>
<input id="bouton" type="submit" value="Envoyer" />
</p>
</form>

</body>
</html>

traitement.html :

Formulaire en cours de traitement.

exo-1.css :

.erreur
{
color: red;
margin-left: 1em;
display: none;
}

exo-1.js :

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");

$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée dans nom");
var texte=$("#nom").val();
$('#erreur-nom').toggle(/[^a-zA-Z '-]/.test(texte));
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
});

$('#email').keyup(function(event)
{
console.log("Une touche a été appuyée dans email");
var email=$('#email').val();
$('#erreur-email').toggle(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i.test(email)===false);
});
$('#mdp').keyup(function(event)
{
console.log("Une touche a été appuyée dans mdp");
var mdp=$('#mdp').val();
$('#erreur-mdp').toggle(mdp.length<6);
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('#confirm').keyup(function(event)
{
console.log("Une touche a été appuyée dans confirm");
var mdp=$('#mdp').val();
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});

$('form').submit(function(event)
{
if($('.erreur:visible').length!==0)
{
event.preventDefault();
alert('Merci de corriger les erreurs.');
}
});


console.log("La mise en place est finie. En attente d'événements...");
});

7. Rappels : sélecteurs CSS

7.1 Rappels : sélecteurs CSS

On va prendre un moment pour revoir les sélecteurs CSS.

Ils seront très utiles non seulement pour la mise en page, mais aussi en JS (notamment dans jQuery).

http://moodle.iutv.univ-paris13.fr/img/web/webs1-cm-3-2-1.png

http://moodle.iutv.univ-paris13.fr/img/web/webs1-tp-1-16.png

http://moodle.iutv.univ-paris13.fr/img/web/webs1-cm-1-17-1.png

Rappels : sélecteurs CSS

7.2 Rappel : arbre des éléments HTML

La notion d'arbre (avec des ancêtres et des descendants) est très utilisée dans les sélecteurs CSS.
Pour comprendre cette notion il faut raisonner sur l'arbre formé par les éléments HTML d'un document.

Voici un exemple d'arbre:

x
Le <a> à gauche est fils (descendant direct) de <h1>
Le <a> à droite est descendant (indirect) de ul.

Rappels : sélecteurs CSS

7.3 Sélecteur de descendants

Un sélecteur CSS sert à dire « je veux appliquer ce style à tels éléments ».

Pour l'instant on a vu

Comment faire pour, par exemple, « appliquer ce style à tous les éléments <a> contenus dans un titre <h1> » ?

r

Prenons un autre exemple:

<ul id="liste1">
<li>abc</li>
<li>def</li>
</ul>

<ul id="liste2">
<li>xyz</li>
<li>rst</li>
</ul>


Supposons qu'on veuille changer uniquement la couleur des "li" de la deuxième liste.
li {color: red;}
ne marche pas, car elle change la couleur des "li" dans les deux listes.

On peut utiliser un sélecteur composé de deux sélecteurs simples:
#liste2 li {color: red;}
L'espace entre "#liste2" et "li" est très important: il veut dire "descendant de".

Donc: "#liste2 li
" veut dire "tous les li qui sont descendants de #liste2


Rappels : sélecteurs CSS

7.4 Descendants - 1

s

Quel(s) élément(s) correspondent au sélecteur suivant?
li a

Rappels : sélecteurs CSS

7.5 Descendants - 2

s
Quel(s) élément(s) correspondent au sélecteur suivant?
ul a

Rappels : sélecteurs CSS

7.6 Descendants

s
Quel(s) élément(s) correspondent au sélecteur suivant?
#grostitre a

Rappels : sélecteurs CSS

7.7 Descendants

s
Quel(s) élément(s) correspondent au sélecteur suivant?
img p

Rappels : sélecteurs CSS

7.8 Descendants

s
Quel(s) élément(s) correspondent au sélecteur suivant?
.auth p img

Rappels : sélecteurs CSS

7.9 Descendants

s
Quel(s) élément(s) correspondent au sélecteur suivant?
#menu .actif

Rappels : sélecteurs CSS

7.10 Descendants directs

descendant direct

Le sélecteur " " (espace) sélectionne les descendants directs et indirects.
Par contre le sélecteur ">" sélectionne uniquement les descendants directs.

Rappels : sélecteurs CSS

7.11 Descendants directs

s
Quel(s) élément(s) correspondent au sélecteur suivant?

p>img

Rappels : sélecteurs CSS

7.12 Descendants directs

s
Quel(s) élément(s) correspondent au sélecteur suivant?

body>a

8. Compositions de sélecteurs

8.1 Compositions de sélecteurs

On peut aussi composer des sélecteurs en les accolant. Regardons ça sur un exemple:

<h1 class="actu">Mon titre</h1>
<p class="actu">
<strong class="actu">abc</strong> defg <a href="...">un lien </a>
</p>

Par exemple, imaginons qu'il y ait de nombreux types d'éléments (des "p" des "h1" ...) ayant tous une même classe "actu". On pourrait alors sélectionner uniquement les paragraphes ayant la classe "actu" comme ceci:
p.actu { color: red;}

(remarquez: il n'y a pas d'espace entre "p" et ".actu")

"p.actu" veut dire : les éléments à la fois de type "p" et appartenant à la classe "actu"

et ensuite on pourrait continuer, par exemple en spécifiant une relation de descendance:

p.actu a { color: red;}

qui veut dire : les éléments "a" contenus dans des paragraphes de classe "actu" seront en rouge

Ce genre d'approche est très utilisée en pratique.

r

On peut faire la même chose avec les id:
ul#menu { color: red;}

Comme il n'y a qu'un seul élément avec id="menu", ceci peut paraître redondant. Mais il y a des situations où c'est utile.

Compositions de sélecteurs

8.2 Composition

s
Quel(s) élément(s) correspondent au sélecteur suivant?
a.actif

Compositions de sélecteurs

8.3 Composition

s
Quel(s) élément(s) correspondent au sélecteur suivant?
ul.actif

Compositions de sélecteurs

8.4 Composition

s
Quel(s) élément(s) correspondent au sélecteur suivant?
p.auth

Compositions de sélecteurs

8.5 Composition

s
Quel(s) élément(s) correspondent au sélecteur suivant?
ul#menu

Compositions de sélecteurs

8.6 Composition

s
Quel(s) élément(s) correspondent au sélecteur suivant?
.auth a.externe img

Compositions de sélecteurs

8.7 Composition

s
Quel(s) élément(s) correspondent au sélecteur suivant?
body.auth h2

9. Priorité des sélecteurs

9.1 Priorité des sélecteurs

Dans les exercices suivants nous allons voir comment des règles des style peuvent s'appliquer indirectement à des éléments et ce qu'il se passe lorsque plusieurs règles différentes s'appliquent à un même élément.

r

La priorité se calcule comme suit:

Priorité des sélecteurs

9.2 Priorité des sélecteurs

Supposons que les sélecteurs suivants s'appliquent tous sur un élément.
Classez les par ordre de priorité (1= le plus prioritaire)

Priorité des sélecteurs

9.3 Priorités CSS : exercice

HTML:

<p id="intro"> 
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>

CSS:

#lienpage { color: red;}
a { color: green;}
.externe { color: blue;}

Quelle est la couleur du mot « page » ?

Priorité des sélecteurs

9.4 Priorités CSS : exercice

HTML:

<p id="intro"> 
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>

CSS:

a.externe { color: red;}
a { color: green;}
#intro a { color: blue;}

Quelle est la couleur du mot « page » ?

Priorité des sélecteurs

9.5 Priorités CSS : exercice

HTML:

<p id="intro"> 
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>

CSS:

#lienpage { color: red;}
#intro .externe { color: green;}
#intro a { color: blue;}

Quelle est la couleur du mot « page » ?

Priorité des sélecteurs

9.6 Priorités CSS : exercice

HTML:

<p id="intro"> 
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>

CSS:

#intro a { color: red;}
a.externe { color: green;}
#intro a .externe { color: blue;}

Quelle est la couleur du mot « page » ?
(attention piège, lisez attentivement)

10. Onglets

10.1 Onglets

Dans les pages suivantes on va réaliser, ensemble, les onglets de la figure de droite.


Si vous êtes en retard, il est préférable d'aller directement à la correction de la partie CSS, cette partie n'etant pas indispensable à l'apprentissage du JavaScript.

11. Onglets : HTML/CSS

11.1 Onglets : HTML/CSS

Commençons par le CSS. 

Dans cette partie, le HTML est fixé. Vous ne devez pas le changer. Vous pouvez uniquement modifier le CSS.

Créez le fichier suivant:

onglets.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>onglets</title>
<link type="text/css" rel="stylesheet" href="onglets.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="onglets.js"></script>
</head>
<body>
<!--------------------->
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>
<!--------------------->
</body>
</html>

Ouvrez aussi un fichier vide "onglets.css"

On va construire, ensemble, étape par étape ces onglets.

Onglets : HTML/CSS

11.2 Onglets CSS 1

On veut d'abord obtenir exactement ceci:

Indications :

Ajoutez l'image de fond suivante à body:

texture-grise.jpg :

Changez la couleur du texte des lignes de la liste en blanc.

Utilisez "float: left;" pour que lignes s'affichent de gauche à droite (et pas de haut en bas)

Utilisez "list-style: none;" sur la liste pour enlever les puces.

On utilise une astuce un peu compliquée pour obtenir le coin coupé :
C'est un dégradé (gradient) penché à 220 degrés avec un passage très court entre transparent et rouge:

background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);

Dans chaque onglet, ajoutez un peu d'espace entre le texte et les bords de l'onglet.


Rappel:

http://moodle.iutv.univ-paris13.fr/img/web/webs1-tp-1-19.png

Onglets : HTML/CSS

11.3 Correction

onglets.css

body
{
background-image: url(texture-grise.jpg);
}

#onglets-menu
{
list-style: none;
}

#onglets-menu li
{
float: left;
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
color: white;
padding: 11px 30px;
}

Onglets : HTML/CSS

11.4 Onglets CSS 2

On veut maintenant obtenir exactement ceci:

Indications :

Texte : Dans chaque onglet, utilisez la police suivante:
font-family: 'Lucida sans', Arial, Helvetica;
Mettez le texte en gras et ajustez sa taille à 12px.
Ajoutez une légère ombre sous le texte (text-shadow).

Relief : Pour l'effet de relief entre les onglets, ajoutez une ombre (voir box-shadow) semi-transparente rgba(0, 0, 0, .2) positionnée à gauche .

menu-actif: Faites en sorte que l'onglet ayant class="menu-actif" soit affiché en blanc.
(pour garder le coin coupé, reprenez la même idée que les autres onglets, en remplaçant la couleur dans le gradient par blanc)
La couleur du texte de l'onglet actif est #333 et il faut lui enlever l'ombre, avec : "text-shadow: none;"

:hover  On veut changer légèrement la couleur d'un onglet quand la souris lui passe par-dessus.
Pour ça, on reprend la même idée que les coins coupés des autres onglets, en remplaçant la couleur dans le gradient par #c93434



Onglets : HTML/CSS

11.5 Correction

onglets.css

body
{
background-image: url(texture-grise.jpg);
}

#onglets-menu
{
list-style: none;
}

#onglets-menu li
{
float: left;
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
color: white;
padding: 11px 30px;
font-family: 'Lucida sans', Arial, Helvetica;
font-weight: bold;
font-size: 12px;
text-shadow: 0 1px 0 rgba(0,0,0,.5);
box-shadow: -4px 0 0 rgba(0, 0, 0, .2);
}

#onglets-menu li:hover
{
background: linear-gradient(220deg, transparent 10px, #c93434 11px);
}

#onglets-menu .menu-actif
{
background: linear-gradient(220deg, transparent 10px, white 11px);
color: #333;
text-shadow: none;
}

/* Forcer à rester blanc quand la souris passe sur le menu actif */
#onglets-menu .menu-actif:hover
{
background: linear-gradient(220deg, transparent 10px, white 11px);
}

Onglets : HTML/CSS

11.6 Onglets complets

On a fini la partie "menu" des onglets. Il nous reste à faire le contenu.

Utilisez cette nouvelle version du fichier onglets.html :

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>onglets</title>
<link type="text/css" rel="stylesheet" href="onglets.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="onglets.js"></script>
</head>
<body>
<!--------------------->
<div id="onglets">
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>

<div id="onglets-contenu">
<div>Martien est un nom générique qui désigne plusieurs types de créatures imaginaires censées vivre sur Mars. Selon la version la plus répandue, les martiens, également nommés « petits hommes verts », sont des êtres à l'apparence vaguement humanoïde et repoussante, minces, avec une grosse tête et des yeux globuleux, généralement animés de mauvaises intentions envers l'espèce humaine. Le nom de martien est souvent devenu, à tort, synonyme d'extraterrestre dans la culture populaire.</div>
<div class="contenu-actif"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
<div>Le chocolat [ ʃɔkɔla ], terme d'origine mésoaméricaine, est un aliment sucré produit à partir de la fève de cacao. Celle-ci est fermentée, torréfiée, broyée jusqu'à former une pâte de cacao liquide dont on extrait la matière grasse appelée beurre de cacao. Le chocolat est constitué du mélange, dans des proportions variables, de pâte de cacao, de beurre de cacao et de sucre ; on y ajoute éventuellement des épices, comme la vanille, ou des matières grasses végétales.</div>
<div><ul><li>Moi: beaucoup</li><li>Eux: pas tant que ça</li></ul></div>
</div>
</div>
<!--------------------->
</body>
</html>

(Dans les pages suivantes, le HTML est encore fixé. Vous ne devez pas le changer. Vous pouvez uniquement modifier le CSS.)


Onglets : HTML/CSS

11.7 Onglets: arbre

Regardons d'abord comment est structuré cet HTML :

<body>
<div id="onglets">
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>

<div id="onglets-contenu">
<div>Martien est un nom générique ...</div>
<div class="contenu-actif">Lorem ipsum dolor sit...</div>
<div>Le chocolat [ ʃɔkɔla ], terme d'origine...</div>
<div>...</div>
</div>
</div>
</body>



Onglets : HTML/CSS

11.8 Onglets contenu : CSS

On veut obtenir ceci:

Indications

Pour s'assurer que <div id="onglets-contenu">  s'affiche après les menus (qui sont float) ajoutez-lui "clear: both;".

On veut réduire la largeur de l'ensemble et le centrer. Pour ça:
Fixez le width de <div id="onglets"> à 600 pixels.
Utilisez margin auto à gauche et à droite pour le centrer.

On veut que "onglets-contenu" soit blanc.

Remarquez que "onglets-menu" n'est pas collé à gauche.
En effet, par défaut un <ul> a du padding à gauche. Il faut l'enlever.


Onglets : HTML/CSS

11.9 Onglets contenu : CSS fin

Dernière étape. On veut obtenir ceci:

http://moodle.iutv.univ-paris13.fr/img/js/onglets.png


Pour l'instant,  tous les <div> dans "onglets-contenu" sont montrés en même temps.
On voudrait les cacher (display: none;) par défaut.
Ensuite, on voudrait montrer (display: block;) un seul, celui qui a class="contenu-actif" .

Complétez tout ce qu'il manque pour obtenir l'affichage ci-dessus.




Onglets : HTML/CSS

11.10 Correction : fin onglets.css

onglets.css

/* Fortement inspiré de : 
* http://red-team-design.com/css3-tabs-with-beveled-corners/
*/

body
{
background-image: url(texture-grise.jpg);
font-family : sans;
}

#onglets
{
width: 600px;
margin: 2em auto;
}

#onglets-menu
{
list-style: none;
padding: 0;
}

#onglets-menu li
{
float: left;
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
color: white;
padding: 11px 30px;
font-family: 'Lucida sans', Arial, Helvetica;
font-weight: bold;
font-size: 12px;
text-shadow: 0 1px 0 rgba(0,0,0,.5);
box-shadow: -4px 0 0 rgba(0, 0, 0, .2);
cursor: pointer;
}

#onglets-menu li:hover
{
background: linear-gradient(220deg, transparent 10px, #c93434 11px);
}

#onglets-menu .menu-actif
{
background: linear-gradient(220deg, transparent 10px, white 11px);
color: #333;
text-shadow: none;
}

/* Forcer à rester blanc quand la souris passe sur le menu actif */
#onglets-menu .menu-actif:hover
{
background: linear-gradient(220deg, transparent 10px, white 11px);
}


#onglets-contenu
{
clear: both;
background-color: white;
border-radius: 0 2px 2px 2px;
box-shadow: 0 2px 2px #000;
}

#onglets-contenu>div
{
display: none;
padding: 30px;
}

#onglets-contenu>.contenu-actif
{
display: block;
}

#onglets-contenu>div>*:first-child
{
margin-top: 0;
}

onglets.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>onglets</title>
<link type="text/css" rel="stylesheet" href="onglets.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="onglets.js"></script>
</head>
<body>
<!--------------------->
<div id="onglets">
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>

<div id="onglets-contenu">
<div>Martien est un nom générique qui désigne plusieurs types de créatures imaginaires censées vivre sur Mars. Selon la version la plus répandue, les martiens, également nommés « petits hommes verts », sont des êtres à l'apparence vaguement humanoïde et repoussante, minces, avec une grosse tête et des yeux globuleux, généralement animés de mauvaises intentions envers l'espèce humaine. Le nom de martien est souvent devenu, à tort, synonyme d'extraterrestre dans la culture populaire.</div>
<div class="contenu-actif"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
<div>Le chocolat [ ʃɔkɔla ], terme d'origine mésoaméricaine, est un aliment sucré produit à partir de la fève de cacao. Celle-ci est fermentée, torréfiée, broyée jusqu'à former une pâte de cacao liquide dont on extrait la matière grasse appelée beurre de cacao. Le chocolat est constitué du mélange, dans des proportions variables, de pâte de cacao, de beurre de cacao et de sucre ; on y ajoute éventuellement des épices, comme la vanille, ou des matières grasses végétales.</div>
<div><ul><li>Moi: beaucoup</li><li>Eux: pas tant que ça</li></ul></div>
</div>
</div>
<!--------------------->
</body>
</html>

12. Onglets : JS

12.1 Onglets : JS

Nos onglets s'affichent bien. On ne va plus toucher aux fichiers HTML et CSS.
On veut maintenant passer d'un onglet à l'autre à l'aide d'un petit programme en JavaScript.

Dans les pages suivantes, on va le faire, ensemble, en deux étapes :

Onglets : JS

12.2 Gestionnaire d'événements


$('span').click(function(e){...});

La fonction anonyme function(e){...} est appelée « gestionnaire d'événements » : son rôle est de réagir lorsqu'un événement survient.

Sur quel(s) élément(s) peut-on cliquer pour provoquer l'appel de la fonction gestionnaire d'événements ?

Onglets : JS

12.3 Liste jQuery


Quelles élément(s) se trouvent dans la liste jQuery suivante ?

$('img')

Onglets : JS

12.4 Gestionnaires d'événements multiple


$('img').click(function(e){...});
On peut installer un gestionnaire d'événements sur plusieurs éléments en même temps.
La même fonction sera appelée quand on clique sur un de ces éléments.

Sur quel(s) élément(s) peut-on cliquer pour provoquer l'appel de la fonction gestionnaire d'événements ?

Onglets : JS

12.5 Rappel : fonctions jQuery : class


Rappel:

un élément peut avoir plusieurs valeurs dans class, séparées par des espaces:

<p class="actu exemple autre-exemple">...</p>

jQuery fourni les fonctions .addClass() et .removeClass() pour ajouter et enlever des noms dans "class".

.hasClass() permet de voir si un nom se trouve dans les valeurs de class.

Pour des affichages complexes, il est préférable d'utiliser "class" que .css(). En utilisant class on écrit uniquement le CSS dans des fichiers CSS. C'est plus propre / lisible.

Onglets : JS

12.6 Rappel : event / this


Quand un événement survient, notre fonction est appelé. Elle reçoit deux informations importantes:

- "event" (en argument): un objet décrivant l'événement, avec des informations comme la position de la souris, le bouton de souris utilisé, la touche appuyée ... On peut omettre cet argument si on n'en a pas besoin.

- "this" : l'objet associé à cette fonction. C'est l'élément DOM sur lequel est survenu l'événement. Dans cet exemple c'est h1. Attention: "this" est un objet DOM. Pour l'utiliser plus facilement, on peut le transformer en liste jQuery : $(this)

Onglets : JS

12.7 Onglets JS : menu

C'est à vous !

En vous inspirant de la structure de tous les fichiers JS vus jusqu'à maintenant, écrivez le code nécessaire pour faire fonctionner le menu (c'est à dire, uniquement la partie d'en haut).

Indications:

Lorsque l'utilisateur clique sur un onglet on doit:

  1. enlever la classe "menu-actif" de l'onglet qui l'a actuellement.
  2. ajouter la classe "menu-actif" à l'onglet sur lequel on vient de cliquer.


Onglets : JS

12.8 Correction

onglets.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
$('#onglets-menu li').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$('.menu-actif').removeClass('menu-actif');
$(this).addClass('menu-actif');
});
console.log("La mise en place est finie. En attente d'événements...");
});


Un petit détail:

on a utilisé "mousedown" au lieu de "click".

mousedown permet donc d'obtenir une réaction un petit peu plus rapide.

Onglets : JS

12.9 Manipulation liste

Passons maintenant à la partie du bas (contenu).

C'est un peu plus compliqué.



Dans cet exemple, l'utilisateur a cliqué sur un onglet.
Grâce à « this », on a l'élément cliqué. On a  donc pu  faire : $(this).addClass('menu-actif');
Mais on n'a pas le <div> contenu correspondant (pour lui ajouter la classe "contenu-actif")

La solution est de :

On va faire ça ensemble.

Onglets : JS

12.10 Liste des onglets




On veut déterminer le numéro du <li> cliqué dans la liste de tous les <li> du menu. (ici ce serait 2 ).
Pour ça, il faut d'abord construire la liste jQuery des <li> dans le menu.
Essayez dans la console.
Que faut-il écrire pour obtenir la liste jQuery des <li> qui sont dans le menu (et uniquement ceux-là) ?

Onglets : JS

12.11 Indice de l'onglet cliqué



On veut déterminer le numéro du <li> cliqué dans la liste de tous les <li> du menu. (ici ce serait 2 ).
La fonction jQuery .index() permet d'obtenir le numéro d'un élément dans une liste jQuery.
Dans onglets.js à l'aide de console.log affichez dans la console le numéro de l'onglet cliqué.
Faites quelques essais.
 

Onglets : JS

12.12 Correction

onglets.js

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
$('#onglets-menu li').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$('.menu-actif').removeClass('menu-actif');
$(this).addClass('menu-actif');

var num=$('#onglets-menu>li').index(this);
console.log("L'utilisateur a cliqué sur l'onglet:",num);
});
console.log("La mise en place est finie. En attente d'événements...");
});

Onglets : JS

12.13 Onglets : fin



On a déterminé le numéro (n) du <li> cliqué.
Maintenant, il nous reste à sélectionner l'élément numéro n dans la liste jQuery des <div> dans "onglets-contenus", et lui ajouter la classe "contenu-actif".
Pour rappel, une liste  jQuery peut être vue comme un tableau. Il existe une fonction jQuery  .eq(n) qui permet de chercher le n-ième élément d'une liste jQuery. Cette fonction .eq(n) renvoie une nouvelle liste jQuery qui contient uniquement ce n-ième élément.

Voila... vous avez tout ce qu'il faut pour faire fonctionner les onglets.
C'est à vous.


Onglets : JS

12.14 Correction

onglets.js

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
$('#onglets-menu li').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$('.menu-actif').removeClass('menu-actif');
$(this).addClass('menu-actif');

$('.contenu-actif').removeClass('contenu-actif');
var num=$('#onglets-menu>li').index(this);
$('#onglets-contenu>div').eq(num).addClass('contenu-actif');
});
console.log("La mise en place est finie. En attente d'événements...");
});

13. Jeu : morpion

13.1 Jeu : morpion

On veut afficher un tableau 3x3

Quand l'utilisateur clique sur une case, un "X" est ajouté.
Pour l'instant on ajoute uniquement des "X", on s'occupera des "O" après.
Écrivez le HTML le CSS et le JS nécessaire pour obtenir exactement le résultat voulu. 

C'est à vous. (Correction à la page suivante)

Jeu : morpion

13.2 Correction

HTML:

<table id="morpion">
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>

CSS:

#morpion 
{
border-collapse: collapse;
}

#morpion td
{
border: 1px solid black;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
cursor: pointer;
}

#morpion td:hover
{
background-color: #ffc;
}

JS:

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#morpion td').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$(this).text('X');
});
console.log("La mise en place est finie. En attente d'événements...");
});

Jeu : morpion

13.3 Fermetures

On veut maintenant que 2 joueurs puissent cliquer, chacun leur tour.

On va donc ajouter une variable joueur. Elle peut valoir "X" ou "O".

JS:

$(document).ready(function()
{
var joueur="X";
$('#morpion td').mousedown(function()
{
// ici on peut utiliser joueur !!!
...
});
});

joueur est déclaré en dehors de la fonction (2) passée à mousedown, mais on peut quand même l'utiliser dedans.

Ça peut paraître simple ou bête, mais c'est une particularité importante du JavaScript qui est très utilisée.
Une fonction qui utilise une variable définie dans une autre fonction extérieure est appelée une fermeture ("closure" en anglais).
En réfléchissant bien, vous vous rendrez compte que c'est plus compliqué qu'il ne semble:
fonction (2) doit se souvenir que joueur est une variable définie dans une autre fonction...
On verra tout ça, plus tard, en détail.

En utilisant joueur, faites en sorte que les 2 joueurs puissent cliquer chacun leur tour.

S'ils cliquent sur une case où il y a déjà quelque-chose, rien ne doit se passer.


Jeu : morpion

13.4 Correction

JS:

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
var joueur="X";

$('#morpion td').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
if($(this).text()!==''){return;}
$(this).text(joueur);
joueur=(joueur==="X" ? 'O' : 'X');
});

console.log("La mise en place est finie. En attente d'événements...");
});