Exercices TP-8

  1. Bienvenue au TP-8
  2. Révisions : divers
    1. Types : number
    2. Type : number
    3. Type : object
    4. .css()
    5. .addClass()
    6. .hide()
    7. .attr
    8. .append()
    9. .offset()
    10. Ordre d'execution
  3. Révisions : listes & arbres
    1. Liste jQuery
    2. Liste jQuery 2
    3. Liste jQuery 3
    4. Liste jQuery .eq() erreur
    5. .children()
    6. .children().eq(2)
    7. .find()
    8. .children() erreur
    9. .children('p')
    10. .click()
    11. Bubbling
  4. Révisions : Ajax
    1. .get() 1
    2. $.get() 2
    3. $.get() 3
    4. Ordre d’exécution
    5. URL GET
    6. URL POST
    7. type reponse
    8. type JSON
    9. Content-Type
    10. json_encode
    11. JSON: objet
    12. JSON: tableau
    13. JSON: tableau dans objet
  5. Cours : HTML & texte
    1. Entités
    2. jQuery : .text()
    3. jQuery : .html()
    4. jQuery : .html()
    5. jQuery : .val()
    6. Exemple
  6. Exercices : HTML & texte
    1. texte->HTML
    2. HTML -> texte
    3. .text()
    4. .html()
    5. .val()
  7. Cours : protocole http
    1. Requêtes & entêtes http
    2. La requête
    3. La réponse
    4. Cookies
  8. Exercices : protocole http
    1. Content-Type
    2. Cookie
    3. Cookie
    4. Cookie
    5. Cookie : identifier qui?
    6. Cookie : identifier qui?
    7. Cookie : prendre identité
  9. Cours : HTML ajouté
    1. jQuery : .is()
    2. Ajout DOM : HTML
    3. Ajout DOM : JS
    4. Ajout DOM : JS
    5. Bubbling
    6. .on()
  10. Exercices : HTML ajouté
    1. Déroulement
    2. $('span')
    3. Ordre
    4. Combien ?
    5. alert ?
    6. alert ?
  11. Cours : Listes jQuery
    1. Listes jQuery
    2. Listes jQuery
    3. Parcours d'arbre
    4. .click()
  12. Exercices : listes jQuery
    1. Types
    2. '.valider'
    3. $('.valider')
    4. this
    5. $(this).parent()
    6. Arg click
  13. Exercices complémentaires
  14. Parties masquables
    1. Masquable HTML
    2. Rappel position absolute
    3. Masquable : CSS
    4. Correction : masquable.css
    5. Masquable : JS simple
    6. Correction: masquable js simple
    7. Masquable : JS avec animation
    8. Correction: masquable.js avec animation
  15. Déplacer
    1. Déplacer : HTML + CSS
    2. JS: première étape : déplacement simple
    3. Correction
    4. Deuxième étape : gérer le bouton
    5. Correction
    6. Troisième étape : calculer la position de la boite
    7. Correction: deplacer.js
  16. Diaporama : extension
    1. Correction
    2. Morpion : extension
    3. Correction
  17. Potentiomètres
    1. Potentiomètre : HTML
    2. Potentiomètre : CSS
    3. Correction: potentiomètre CSS
    4. Potentiomètre JS
    5. Correction : potentiomètre JS
  18. Couleur
    1. Couleur : HTML et CSS
    2. Correction: HTML et CSS
    3. Couleur : JS
    4. Correction : couleur.js
  19. Fin

1. Bienvenue au TP-8

1.1 Bienvenue au TP-8

2. Révisions : divers

2.1 Révisions : divers

Commençons ce dernier TP par des révisions approfondies

Révisions : divers

2.2 Types : number

var a=3.14159;

Quel est le type de la variable a ?
(type "officiel" JS en anglais)

Révisions : divers

2.3 Type : number

var a=123;
Quel est le type de la variable a ?
(type "officiel" JS en anglais)

Révisions : divers

2.4 Type : object

var a={x:1};
Quel est le type de la variable a ?
(type "officiel" JS en anglais)

Révisions : divers

2.5 .css()

Que faut-il écrire en jQuery pour transformer ceci :

<p id="p1">bonjour</p>
<p id="p2">aurevoir</p>

en ceci :

<p id="p1">bonjour</p>
<p id="p2" style="color: red">aurevoir</p>



Révisions : divers

2.6 .addClass()

Que faut-il écrire en jQuery pour transformer ceci :

<p id="p1">bonjour</p>
<p id="p2">aurevoir</p>

en ceci :

<p id="p1">bonjour</p>
<p id="p2" class="urgent">aurevoir</p>


Révisions : divers

2.7 .hide()

Que faut-il écrire en jQuery pour transformer ceci :

<p id="p1">bonjour</p>
<p id="p2">aurevoir</p>

en ceci :

<p id="p1">bonjour</p>
<p id="p2" style="display: none">aurevoir</p>

Révisions : divers

2.8 .attr

Que faut-il écrire en jQuery pour transformer ceci :

<p id="p1">bonjour</p>
<p id="p2">aurevoir</p>

en ceci :

<p id="p1">bonjour</p>
<p id="p2" data-xyz="ijkl">aurevoir</p>

Révisions : divers

2.9 .append()

var s=$('<span>aurevoir</span>');
XXXX

Que faut-il écrire en jQuery à la place de XXXX pour transformer ceci :

<p id="p2"><span>bonjour</span></p>

en ceci :

<p id="p2"><span>bonjour</span><span>aurevoir</span></p> 



Révisions : divers

2.10 .offset()

CSS

#p1
{
position: absolute;
}
HTML
<div id="popup">bonjour</div>

JS

$('#popup').offset(XXXX);

Que faut-il écrire à la place de XXXX pour que le div se retrouve aux coordonnées x (100) et y (200)  de la page ?

Révisions : divers

2.11 Ordre d'execution


console.log('A');
$('p').click(function()
{
console.log('B');
});
console.log('C');

Déterminez l'ordre :

3. Révisions : listes & arbres

3.1 Révisions : listes & arbres

Révisions : listes & arbres

3.2 Liste jQuery


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('li')

Révisions : listes & arbres

3.3 Liste jQuery 2


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#actif')

Révisions : listes & arbres

3.4 Liste jQuery 3


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#actif').parent()

Révisions : listes & arbres

3.5 Liste jQuery .eq() erreur


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#actif').parent().eq(2)

Révisions : listes & arbres

3.6 .children()


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#actif').parent().children()

Révisions : listes & arbres

3.7 .children().eq(2)


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#actif').parent().children().eq(2)

Révisions : listes & arbres

3.8 .find()


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#menu').find('a')

Révisions : listes & arbres

3.9 .children() erreur


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#menu').children('a')

Révisions : listes & arbres

3.10 .children('p')


Quel(s) élément(s) sont contenus dans la liste jQuery suivante ?

$('#menu').children('p')

Révisions : listes & arbres

3.11 .click()


$('#actif').click(function()
{
console.log('ok');
});

Sur quels éléments peut-on cliquer pour afficher 'ok' dans la console ?

Révisions : listes & arbres

3.12 Bubbling


$('ul').click(function()
{
console.log('ok');
});
Sur quels éléments peut-on cliquer pour afficher 'ok' dans la console ?

4. Révisions : Ajax

4.1 Révisions : Ajax

Révisions : Ajax

4.2 .get() 1

Donnez un exemple de ce que pourrait être le premier argument de la fonction jQuery $.get()

Révisions : Ajax

4.3 $.get() 2

Donnez un exemple de ce que pourrait être le deuxième argument de la fonction jQuery $.get()

Révisions : Ajax

4.4 $.get() 3

Donnez un exemple de ce que pourrait être le troisième argument de la fonction jQuery $.get()

Révisions : Ajax

4.5 Ordre d’exécution


console.log('A');
$.get('http://exemple.org/liste.php',
{
group: 'equipe-5',
id: 321
},
function(reponse)
{
console.log('B');
});
console.log('C');

Quel est l'ordre d'exécution ?

Révisions : Ajax

4.6 URL GET


console.log('A');
$.get('http://exemple.org/liste.php',
{
group: 'equipe-5',
id: 321
},
function(reponse)
{
console.log('B');
});
console.log('C');

Quel est l'URL effectivement utilisée lors de cette requête ?

Révisions : Ajax

4.7 URL POST


console.log('A');
$.post('http://exemple.org/liste.php',
{
group: 'equipe-5',
id: 321
},
function(reponse)
{
console.log('B');
});
console.log('C');
Quel est l'URL effectivement utilisée lors de cette requête ?
(attention: .get() a été remplacé en .post() )

Révisions : Ajax

4.8 type reponse

PHP

<?php
echo "bonjour";
?>

JS

console.log('A');
$.post('http://exemple.org/liste.php',
{
group: 'equipe-5',
id: 321
},
function(reponse)
{
console.log('B');
});
console.log('C');

Quel est le type de la variable reponse ?

Révisions : Ajax

4.9 type JSON


JS

console.log('A');
$.post('http://exemple.org/liste.php',
{
group: 'equipe-5',
id: 321
},
function(reponse)
{
console.log('B');
});
console.log('C');

Au lieu de récupérer un « string  » dans réponse, on voudrait récupérer un objet contenant différents champs.

Quel est le nom du format de réponse que le serveur doit envoyer au navigateur ?
(le format vu en cours)

Révisions : Ajax

4.10 Content-Type

Quel est le nom de l'entête http que le serveur envoie au navigateur pour lui dire que le contenu est en JSON (et pas en html).

On vous demande uniquement le nom de l'entête, pas sa valeur.

Révisions : Ajax

4.11 json_encode

Quel est le nom de la fonction PHP permettant de convertir un tableau PHP en JSON ?

Révisions : Ajax

4.12 JSON: objet


Qu'affiche le code suivant ?


<?php
$a=array();
$a['xyz']=123;
header('Content-Type: application/json');
echo json_encode($a);
?>

Révisions : Ajax

4.13 JSON: tableau

Qu'affiche le code suivant ?


<?php
$a=array('abc','def');
header('Content-Type: application/json');
 echo json_encode($a);
?>

Révisions : Ajax

4.14 JSON: tableau dans objet

Qu'affiche le code suivant ?


<?php
$a=array();
$a['xyz']=array('abc','def')
header('Content-Type: application/json');
  echo json_encode($a);
?>

5. Cours : HTML & texte

5.1 Cours : HTML & texte

Si vous venez d'assister au cours magistral, passez à la section suivante.

Cours : HTML & texte

5.2 Entités

Le HTML et le texte « brut » se ressemblent beaucoup, mais sont en réalité deux formats différents. Les confondre peut conduire à des problèmes d'affichage et, plus grave, à des problèmes de sécurité.

En HTML, certains caractère ont un sens particulier. Par exemple "<" est le début d'une balise. Si on veut représenter ces caractères, on doit utiliser les « entités » correspondantes. Dans cet exemple on doit utiliser "&lt;" au lieu de ">"

Cours : HTML & texte

5.3 jQuery : .text()

La fonction jQuery .text() permet de lire le texte contenu dans un élément. .text('...') permet de créer / remplacer du texte.

Si vous utilisez .text('...') sur un élément qui contient déjà d'autres éléments, ils sont tous supprimés avant que votre texte soit ajouté.

Dans l'arbre DOM le texte est représenté par des noeuds Text. En général, on ne les dessine pas sur les schémas, mais ils existent bien dans l'arbre.

La fonction .text('...') ajoute bien du texte et pas du HTML. Les caractères spéciaux (comme le ">") sont correctement gérés.

Cours : HTML & texte

5.4 jQuery : .html()

Il ne faut pas confondre .text() et .html().

.html('...') permet d'ajouter du html à l'intérieur d'éléments existants dans l'arbre.

D'abord, tout le contenu de l'élément cible est supprimé.

Ensuite, le HTML à ajouter est transformé en un fragment d'arbre DOM qui est ensuite inséré dans l'arbre.

Cours : HTML & texte

5.5 jQuery : .html()

Si on utilise .text() à la place de .html(), les balises ne sont pas transformés en éléments de l'arbre: elles sont considérées comme du texte.

Cours : HTML & texte

5.6 jQuery : .val()

Il y a parfois des confusions entre .text() et .val().

Ces deux fonctions ne font pas du tout la même chose.

.val() permet de lire et d'écrire la valeur d'un champs de formulaire.

.text() permet de lire et d'écrire le texte contenu dans un élément de l'arbre.

Cours : HTML & texte

5.7 Exemple

Dans cet exemple, l'utilisateur tape du texte dans un champs texte <input>, puis appuie sur un bouton. La valeur saisie est ensuite affichée à l'aide de .html() dans le paragraphe.

Si l'utilisateur a saisi du texte simple (des lettres ordinaires), le programme fonctionne correctement.

Si l'utilisateur rentre des caractères spéciaux, il peut y avoir des problèmes d'affichage. Par exemple un "<" sera considéré comme un début de balise. C'est embêtant.

On peut imaginer un contexte où un utilisateur malveillant fourni du texte contenant du JS. Plus tard un autre utilisateur (par exemple un admin) lit la page. Si un programme JS copie avec .html() le texte fourni par l'utilisateur malveillant, alors celui-ci pourra voler ses cookies...

6. Exercices : HTML & texte

6.1 Exercices : HTML & texte

Exercices : HTML & texte

6.2 texte->HTML

Traduisez ce fragment de texte en HTML.

Score Karim > score Joe. L'équipe 2 a perdu.


Exercices : HTML & texte

6.3 HTML -> texte

Traduisez ce fragment de HTML en texte.

Joe dit &quot;Bonjour Karim&quot;


Exercices : HTML & texte

6.4 .text()

Que faut-il écrire en jQuery pour transformer ceci :

<span id="ville"></span>

en ceci :

<span id="ville">Pont l&apos;Evêque</span>

Exercices : HTML & texte

6.5 .html()

Que faut-il écrire en jQuery pour transformer ceci :

<p id="message"></p>

en ceci :

<p id="message">Je suis <strong>content</strong></p>

Exercices : HTML & texte

6.6 .val()

Que faut-il écrire en jQuery pour transformer ceci :

<input id="nom" type="text"/>

en ceci :

<input id="nom" type="text" value="Joe"/>

7. Cours : protocole http

7.1 Cours : protocole http

Si vous venez d'assister au cours magistral, passez à la section suivante.

Cours : protocole http

7.2 Requêtes & entêtes http

La communication entre le navigateur et le serveur se fait dans un langage (protocole) appelée "http". On peut l'imaginer comme une « discussion ».

Dans une requête GET simple, le navigateur envoie des informations au serveur. Ces informations ne sont pas visibles par l'utilisateur. Ce sont des « entêtes » http.

De même, la réponse du serveur contient à la fois des « entêtes » invisibles et le « corps » : le HTML.

Les entêtes étant invisibles, on a tendance à les oublier. Elles jouent pourtant un rôle important.

(Attention à ne pas confondre les entêtes <head> du HTML et les entêtes du http. Les entêtes <head> du HTML se trouvent dans le corps de la réponse HTTP)

Cours : protocole http

7.3 La requête

On peut imaginer l'échange entre le navigateur et le serveur comme une « discussion » dans un langage appelé « http ». Elle est traduite en français ici.

Ici, le navigateur demande une page au serveur.

Il envoie de nombreuses informations pour indiquer au serveur qu'il il est, ce qu'il veut, et ce qu'il est capable d'accepter comme réponse.

Cette requête GET ne contient que des entêtes (pas de corps).

Toutes ces informations sont visibles à l'aide de Firebug (onglet Réseau).

Cours : protocole http

7.4 La réponse

Le serveur répond. Il envoi un code pour dire au navigateur s'il a bien réussi (200) à fournir la page demandée. Quelques exemples de codes d'erreur : 404, 500,...

Cette réponse contient à la fois des entêtes et un corps (du HTML).

Une information importante est le « Content-Type ». Elle dit au navigateur comment il doit afficher le corps.text/html : il doit l'afficher en tant que HTML

image/png : il doit l'afficher en tant qu'image

...

En programmation web, on a souvent besoin d'indiquer le Content-Type.

Cours : protocole http

7.5 Cookies

Une des informations cruciales transmises dans les entêtes est le cookie.

Les cookies sont initialement fournis par le serveur. Ensuite, à chaque requête, le navigateur renvoie le cookie au serveur. De cette manière, le serveur peut identifier un utilisateur précis.

C'est ce mécanisme qui permet d'attribuer des identités à des utilisateurs (connexion à un compte, ...).

Un cookie de session doit rester secret. Si un utilisateur malveillant réussi à connaître votre cookie, il peut prendre votre identité.

Ca peut arriver si le développeur (PHP, JS, ...) confond HTML et texte... ouvrant la voie à une attaque appelée XSS

8. Exercices : protocole http

8.1 Exercices : protocole http

Exercices : protocole http

8.2 Content-Type

Ouvrez le fichier suivant dans votre navigateur ;

http://moodle.iutv.univ-paris13.fr/img/js/exemple.css

Ouvrez l'onglet "Réseau" de Firebug et rechargez complètement la page (attention: il faut appuyer sur maj+bouton pour forcer le rechargement)

Analysez les entêtes de la requête et de la réponse.

Dans la réponse, quel est la valeur de Content-Type

Exercices : protocole http

8.3 Cookie

Trouvez dans la requête le champs Cookie.

Dans le Cookie, quel est le mot qui commence par Moodle ?

Exercices : protocole http

8.4 Cookie

Le Cookie est une information envoyée à chaque requête du serveur au navigateur.

Exercices : protocole http

8.5 Cookie

Le Cookie est une information envoyée à chaque requête du navigateur au serveur.

Exercices : protocole http

8.6 Cookie : identifier qui?

Le Cookie permet au navigateur d'identifier le serveur

Exercices : protocole http

8.7 Cookie : identifier qui?

Le Cookie permet au serveur d'identifier le navigateur 

Exercices : protocole http

8.8 Cookie : prendre identité

Si une personne A connaît le Cookie d'une personne B, alors A peut prendre l'identité de B

9. Cours : HTML ajouté

9.1 Cours : HTML ajouté

Si vous venez d'assister au cours magistral, passez à la section suivante.

Cours : HTML ajouté

9.2 jQuery : .is()

La fonction jQuery .is() permet de vérifier si un élément correspond bien à un sélecteur.

C'est souvent utilisé dans les gestionnaires d'événements où "this" peut prendre plusieurs valeurs.

Cours : HTML ajouté

9.3 Ajout DOM : HTML

Dans cet exemple, un utilisateur peut saisir du texte dans un champs texte puis appuyer sur un bouton. Le texte saisi est alors ajouté à une liste.

On veut aussi que l'utilisateur faire une action quand l'utilisateur clique sur les éléments de la liste.

Cours : HTML ajouté

9.4 Ajout DOM : JS

Le JS est constitué de deux parties:

1) le gestionnaire d'événements permettant d'ajouter le texte saisi à la liste

2) le gestionnaire d'événements pour faire une action quand l'utilisateur clique sur un élément de la liste.

Cours : HTML ajouté

9.5 Ajout DOM : JS

Ce code contient un bug. Pour le comprendre, il faut suivre, étape par étape, le déroulement du programme.

1) les gestionnaire de click est ajouté. Mais pour l'instant l'utilisateur n'a pas cliqué. Donc la ligne "Wang" n'existe pas encore

2) On ajoute le gestionnaire mousedown sur les lignes existantes. Donc sur les deux premières (Wang n'existe pas encore).

3) l'utilisateur clique et

4) la ligne Wang est ajoutée

Si l'utilisateur fait mousedown sur Wang, rien ne se passe... :-(

Cours : HTML ajouté

9.6 Bubbling

Pour remédier à ce problème, deux solutions différentes sont possibles.

1) ajouter un gestionnaire juste après le append(). Ca demande de réorganiser / dupliquer du code.

2) profiter du "bubbling"

On va préférer la (2)

L'événement mousedown est d'abord transmis à <li> puis à son père <ul>, puis à son père <body>...

On peut don installer le gestionnaire mousedown sur <ul> au lieu de <li>. <ul> est bien présent au démarrage du programme.

Il reste alors à vérifier dans le gestionnaire que l'utilisateur a bien cliqué sur un <li> (et pas sur le <ul>).

Cours : HTML ajouté

9.7 .on()

Cette opération est très courante. jQuery fourni donc une fonction appelée .on() qui permet de le faire simplement.

Remarquez que dans .on() "this" est <li> alors que que dans $('ul').mousedown() vu à la page précédente, this était <ul>.

.on() est plus pratique.

10. Exercices : HTML ajouté

10.1 Exercices : HTML ajouté

Exercices : HTML ajouté

10.2 Déroulement

HTML

<body>
<p id="p1"><span>bonjour</span></p>
<p id="p2"></p>
<body>

JS

$(document).ready(function()
{
console.log('A');
$('#p1').click(function()
{
console.log('B');
$('#p2').html('<span>aurevoir</span>');
console.log('C');
});
console.log('D');
$('span').css('color','red');
console.log('E');
});

Prenez le temps de bien comprendre le déroulement de ce programme.

Quel est l'ordre ?

Exercices : HTML ajouté

10.3 $('span')

HTML
<body>
<p id="p1"><span>bonjour</span></p>
<p id="p2"></p>
<body>

JS

$(document).ready(function()
{
console.log('A');
$('#p1').click(function()
{
console.log('B');
$('#p2').html('<span>aurevoir</span>');
console.log('C');
});
console.log('D');
$('span').css('color','red');
console.log('E');
});
L'utilisateur clique une fois sur le premier paragraphe.
Combien de <span> sont affichés en rouge ?

Exercices : HTML ajouté

10.4 Ordre

HTML

<body>
<p id="p1"><span>bonjour</span></p>
<p id="p2"></p>
<body>

JS

$(document).ready(function()
{
console.log('A');
$('#p1').click(function()
{
console.log('B');
$('#p2').html('<span>aurevoir</span>');
console.log('C');
});
console.log('D');
$('#p2 span').click(function()
{
alert('click span');
});

console.log('E');
});
L'utilisateur clique d'abord sur le 1er paragraphe, ensuite sur le <span> du deuxième.
Quel est l'ordre d'exécution ?

Exercices : HTML ajouté

10.5 Combien ?

HTML

<body>
<p id="p1"><span>bonjour</span></p>
<p id="p2"></p>
<body>

JS

$(document).ready(function()
{
console.log('A');
$('#p1').click(function()
{
console.log('B');
$('#p2').html('<span>aurevoir</span>');
console.log('C');
});
console.log('D');
$('#p2 span').click(function()
{
alert('click span');
});
console.log('E');
});

Après "D", combien d'éléments est-ce qu'il y a dans la liste jQuery  $('#p2 span') 

Exercices : HTML ajouté

10.6 alert ?

HTML

<body>
<p id="p1"><span>bonjour</span></p>
<p id="p2"></p>
<body>

JS

$(document).ready(function()
{
console.log('A');
$('#p1').click(function()
{
console.log('B');
$('#p2').html('<span>aurevoir</span>');
console.log('C');
});
console.log('D');
$('#p2 span').click(function()
{
alert('click span');
});
console.log('E');
});
L'utilisateur clique d'abord sur le 1er paragraphe, ensuite sur le <span> du deuxième.
Est-ce que l'alert est affiché ?

Exercices : HTML ajouté

10.7 alert ?

HTML

<body>
<p id="p1"><span>bonjour</span></p>
<p id="p2"></p>
<body>

JS

$(document).ready(function()
{
console.log('A');
$('#p1').click(function()
{
console.log('B');
$('#p2').html('<span>aurevoir</span>');
console.log('C');
});
console.log('D');
$('#p2').click(function()
{
alert('click span');
});
console.log('E');
});
Attention: changement de code: $('#p2 span') devient $('#p2')

L'utilisateur clique d'abord sur le 1er paragraphe, ensuite sur le <span> du deuxième.
Est-ce que l'alert est affiché ?

11. Cours : Listes jQuery

11.1 Cours : Listes jQuery

Si vous venez d'assister au cours magistral, passez à la section suivante.

Cours : Listes jQuery

11.2 Listes jQuery

Les listes jQuery sont omniprésentes.

On peut les créer de plusieurs manières :

1) à partir d'un sélecteur CSS. ex: $('#ajouter')

2) à partir de HTML. ex: $('<li></li>')

3) à partir d'un élément DOM. ex: $(this)

Dans tous les cas, il s'agit bien d'une liste jQuery. On peut appliquer les presque 200 fonctions associées aux listes jQuery.

Une liste jQuery peut être vue comme un tableau. On manipule souvent des listes avec un seul élément.

Les listes peuvent, bien sur, être affectées à des variables, passées en argument à des fonctions, etc.

Cours : Listes jQuery

11.3 Listes jQuery

Dans tous ces exemples on manipule une même liste, constituée des trois éléments h2, p et span.

Cette liste peut être vue comme un tableau.

La fonction .eq() permet d’accéder aux éléments de ce tableau. Elle renvoie une liste jQuery ne contenant qu'un seul élément.

De manière similaire, l'opérateur [ ] (crochets) permet d’accéder à un élément. Il renvoie un élément DOM.

Comme pour un tableau, on peut utiliser .length

Dans toutes ces opérations, il n'y a pas de parcours d'arbre.

Cours : Listes jQuery

11.4 Parcours d'arbre

Les fonction jQuery renvoient en général une nouvelle liste jQuery. On peut donc les enchaîner.

Remarquez qu'à chaque fois la fonction jQuery est appliquée sur le résultat de la précédente fonction jQuery.

Cours : Listes jQuery

11.5 .click()

$('.ok') est une liste contenant 3 éléments.

Donc .click() est appelé sur 3 éléments

Le gestionnaire d'événements est bien ajouté 3 fois.

Remarquez ici un effet probablement non-souhaité :

Si on clique sur <span>, le gestionnaire va être appelée un première fois. Ensuite par "bubbling" l'événement remonte à <p>. Le gestionnaire est donc appelé une 2e fois.

12. Exercices : listes jQuery

12.1 Exercices : listes jQuery

Exercices : listes jQuery

12.2 Types

JS

$(document).ready(function()
{
$('.valider').click(function()
{
$(this).parent().css('color','red');
});

});

Qu'est : document

Exercices : listes jQuery

12.3 '.valider'

JS

$(document).ready(function()
{
$('.valider').click(function()
{
$(this).parent().css('color','red');
});

});
Qu'est : '.valider'

Exercices : listes jQuery

12.4 $('.valider')

JS

$(document).ready(function()
{
$('.valider').click(function()
{
$(this).parent().css('color','red');
});

});
Qu'est : $('.valider')

Exercices : listes jQuery

12.5 this

JS

$(document).ready(function()
{
$('.valider').click(function()
{
$(this).parent().css('color','red');
});

});
Qu'est : this

Exercices : listes jQuery

12.6 $(this).parent()

JS

$(document).ready(function()
{
$('.valider').click(function()
{
$(this).parent().css('color','red');
});

});
Qu'est : $(this).parent()

Exercices : listes jQuery

12.7 Arg click

JS

$(document).ready(function()
{
$('.valider').click(function()
{
$(this).parent().css('color','red');
});

});
Qu'est : l'argument passé à .click()

13. Exercices complémentaires

13.1 Exercices complémentaires

14. Parties masquables

14.1 Parties masquables

On voudrait créer un affichage comme celui de droite.Chaque partie peut-être ouverte ou fermée en cliquant sur son titre.

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

  1. le CSS
  2. le JS simple, sans animation
  3. le JS avec animation




Parties masquables

14.2 Masquable HTML

Créez des fichiers vides masquable.css et masquable.js

Créez aussi le fichier HTML suivant :

masquable.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>masquable</title>
<link type="text/css" rel="stylesheet" href="masquable.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="masquable.js"></script>
</head>
<body>
<!--------------------->
<div class="masquable">
<h2 class="masquable-titre"><span>-</span>Première partie</h2>
<div class="masquable-contenu">
<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. 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>

<div class="masquable ferme">
<h2 class="masquable-titre"><span>+</span>Deuxième partie</h2>
<div class="masquable-contenu">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</p>
</div>
</div>

<div class="masquable ferme">
<h2 class="masquable-titre"><span>+</span>Troisième partie</h2>
<div class="masquable-contenu">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
</p>
</div>
</div>

<!--------------------->
</body>
</html>

Parties masquables

14.3 Rappel position absolute

Avant de faire le CSS, commençons par un rappel sur "position: absolute"

http://moodle.iutv.univ-paris13.fr/img/web/webs1-tp-5-2.png

Quand un élément (ici l'image) a « position: absolute », il n'affecte plus du tout le positionnement des autres éléments ou texte autour. Il s'affiche donc « par-dessus » ou « par-dessous » les éléments l'entourant.

Tout seul « position: absolute » n'est pas très utile. Par contre, une fois qu'un élément est « position: absolute », on peut le déplacer facilement avec les propriétés « top, left, right, bottom »:

http://moodle.iutv.univ-paris13.fr/img/web/webs1-tp-5-3.png


Les coordonnées "top,left,bottom et right" sont relatives au "block contenant" ("containing block").

Si rien de particulier est fait, le "containing block" est la page.
Tout block qui a "position:absolute" ou bien "position: relative" devient lui-même un "containing block"

Quand on veut juste transformer un block en "containing block", on ne peut pas utiliser "position:absolute", car il change l'affichage du block.
On utilise donc "position: relative.




Parties masquables

14.4 Masquable : CSS

Écrivez le CSS pour obtenir exactement l'affichage de la figure, sans changer le HTML.

Quelques indications :







Parties masquables

14.5 Correction : masquable.css

masquable.css

body
{
font-family: sans;
}

.masquable
{
/* Par défaut bordure complète */
border: 1px solid #aaa;
/* Sert uniquement à créer un "containing élément" pour pouvoir placer le titre avec position: absolute */
position: relative;
margin: 2em 0;
}

.masquable.ferme
{
/* La boite ferme n'a que border-top (sinon trait épais) */
border: none;
border-top: 1px solid #aaa;
}

.masquable-titre
{
/* Permet de placer le titre dans .masquable (qui est "containing bloc") */
position: absolute;
font-size: 14px;
/* coordonnées relatives au "containing bloc" */
top: -11px;
left: 20px;
/* On ne veut pas que le titre fasse toute la ligne */
display: inline-block;
padding-left: 1em;
padding-right: 1em;
background-color: white;
cursor: pointer;
margin: 0;
}

/* Quand c'est ouvert les bordures font bouger légèrement le titre. Il faut compenser de 1px */
.masquable.ferme>.masquable-titre
{
left: 21px;
}


/* La petite boite avec "+" ou "-" */
.masquable-titre span
{
margin-right: 1em;
border: 1px solid #aaa;
display: inline-block;
width: 16px;
height: 16px;
text-align: center;
}

.masquable-titre:hover span
{
background-color: #ffc;
}


.masquable-contenu
{
padding: 1em;
overflow: hidden;
}

.masquable.ferme .masquable-contenu
{
/* Quand c'est ferme , on cache le contenu. */
/* On ne peut pas se contenter de le faire dans le JS... */
/* car on veut pouvoir avoir des parties fermées dès l'affichage initial */
/* (qui se fait en HTML+CSS seuls) */
display: none;
}


/* Éviter que le contenu ne commence par de l'espace vide */
.masquable-contenu>*:first-child
{
margin-top: 0;
}

/* Éviter que le contenu ne finisse par de l'espace vide */
.masquable-contenu>*:last-child
{
margin-bottom: 0;
}

Parties masquables

14.6 Masquable : JS simple

Commencez par une version simple de masquable.js :

On veut montrer / fermer les boites sans animation.

Écrivez le fichier masquable.js sans modifier le HTML.

Parties masquables

14.7 Correction: masquable js simple

masquable.js

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

$('.masquable-titre').mousedown(function(e)
{
console.log("Le bouton de la souris a été appuyé sur le titre");
// Seulement le bouton gauche de la souris
if(e.which!==1){return;}
// Éviter que l'utilisateur ne sélectionne du texte s'il bouge la souris tout en cliquant
e.preventDefault();
var masquable=$(this).parent();
var contenu=masquable.children('.masquable-contenu');
// Déterminer si c'est actuellement fermé ou ouvert en regardant la classe
var ferme=masquable.hasClass("ferme");
// Changer le + en - ou le "-" en "+"
masquable.children('.masquable-titre').find('span').text(ferme ? '-' : '+');
masquable.toggleClass("ferme",!ferme);
});

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

Parties masquables

14.8 Masquable : JS avec animation

On veut améliorer l'affichage en animant l'ouverture et la fermeture.

Pour ça on va utiliser les fonctions jQuery .slideUp() et .slideDown()

Indications :


Parties masquables

14.9 Correction: masquable.js avec animation

masquable.js

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

$('.masquable-titre').mousedown(function(e)
{
console.log("Le bouton de la souris a été appuyé sur le titre");
// Seulement le bouton gauche de la souris
if(e.which!==1){return;}
// Éviter que l'utilisateur ne sélectionne du texte s'il bouge la souris tout en cliquant
e.preventDefault();
var masquable=$(this).parent();
var contenu=masquable.children('.masquable-contenu');
// Déterminer si c'est actuellement fermé ou ouvert en regardant la classe
var ferme=masquable.hasClass("ferme");
// Changer le + en - ou le "-" en "+"
masquable.children('.masquable-titre').find('span').text(ferme ? '-' : '+');
if(ferme)
{
masquable.removeClass('ferme');
// Quand on enleve la classe "ferme", le contenu devient visible... et donc .slideDown() n'a pas d'effet.
// On doit donc cacher le contenu, et laisser .slideDown() le re-afficher.
contenu.hide();
contenu.slideDown();
}
else
{
// Si on ajoute la classe "ferme" toute de suite, le contenu sera caché, et il n'y aura plus que border-top.
// Donc... on laisse ouvert jusqu'à la fin de l'animation...
// Le deuxième argument de .slideUp() est une fonction à appeler quand l'animation est finie.
contenu.slideUp(400,function(){masquable.addClass('ferme');});
}
});

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

15. Déplacer

15.1 Déplacer


Dans les pages suivantes on va écrire, ensemble, un petit programme permettant de déplacer des boites avec la souris.


Déplacer

15.2 Déplacer : HTML + CSS

Créez les deux fichiers suivants:

deplacer.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>deplacer</title>
<link type="text/css" rel="stylesheet" href="deplacer.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="deplacer.js"></script>
</head>
<body>
<!--------------------->
<h2 class="deplacer">Déplace moi !</h2>
<h2 class="deplacer">Déplace moi aussi !</h2>
<!--------------------->
</body>
</html>

deplacer.css

.deplacer
{
display: inline-block;
position: absolute;
background-color: #6a3;
border: 1px solid black;
box-shadow: 2px 2px 2px rgba(0,0,0,.2);
color: white;
padding: .5em;
/* La souris est une petite main */
cursor: grab;
}

.deplacer.en-mouvement
{
background-color: #9c3;
/* La souris est une petite main active */
cursor: grabbing;
}

/* Position de départ de la 2e boite */
.deplacer:nth-child(2)
{
top: 100px;
}


Prenez le temps de comprendre le CSS.

Tout est « esthétique » sauf les deux lignes suivantes:

	display: inline-block;
position: absolute;

Déplacer

15.3 JS: première étape : déplacement simple

On va décomposer en 3 étapes :
  1. faire bouger une boite, suivant en permanence la souris
  2. gérer l'appui et le relâchement du bouton de la souris
  3. calculer la bonne position de la boite.

--

Première étape

Avant de commencer, n'hésitez pas à regarder le TP-1 où l'on a vu les mouvements de la souris (exercice avec la peinture verte sur le pingouin).

Dans le fichier HTML, ajoutez la classe "en-mouvement", à la main, à une des deux boites vertes.

On veut que le coin en haut à gauche de la boite qui a la classe "en-mouvement" se trouve toujours à la même position que la souris.

Il vaut mieux suivre les mouvements de la souris sur l'élément <html> qu'à l'intérieur des boites.
Si on suivait à l'intérieur de la boite, un grand mouvement de la souris pourrait faire sortir le pointeur de la boite et on "perdrait" la boite.
(On profite du bubbling : même si l'événement mouvement se produit dans la boite, il "remonte" l'arbre DOM jusqu'à l'élément <html>. On peut donc utiliser un gestionnaire d'événements sur <html>, même si l'événement se produit dans la boite <h2>.)

Vous pouvez utiliser la fonction jQuery .offset() pour positionner la boite.

Ensuite, dans le fichier HTML, à la main, enlevez la classe "en-mouvement", de la boite pour la mettre sur l'autre boite.
Vérifiez que ca marche.

Ensuite, n'oubliez d'enlever la classe "en-mouvement" des deux boites vertes.


Déplacer

15.4 Correction

deplacer.js

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

// On suit les mouvements sur toute la page.
// Si on suivait uniquement à l'intérieur de la boite un
// grand mouvement de la souris pourrait faire sortir le pointeur de la boite et
// on "perdrait" la boite.
$('html').mousemove(function(event)
{
console.log("La souris à bougé dans la page");
var boite=$('.en-mouvement');
var pos={left:event.pageX,
top: event.pageY};
boite.offset(pos);
});

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

Déplacer

15.5 Deuxième étape : gérer le bouton

On veut démarrer et arrêter le mouvement avec le bouton de la souris :


Les événements de la souris sont documentés ici:

http://api.jquery.com/category/events/mouse-events/
http://openclassrooms.com/courses/dynamisez-vos-sites-web-avec-javascript/les-evenements-24


Remarque: gérez le relâchement de la souris sur l'élément <html> et pas directement sur la boite verte.
En effet, si la souris bouge elle peut sortir de la boite verte et le bouton peut-être relâché en dehors de cette boite.

Remarque2: une erreur courante est de vouloir ajouter le gestionnaire du mouvement lors de l'appui du bouton. Avec cette approche, a chaque appui du bouton on ajoute un nouveau gestionnaire de mouvement... on se retrouve alors avec de très nombreux appels au gestionnaire de mouvement. Par ailleurs le relâchement du bouton n'est pas simple à gérér. L'approche plus simple (et mieux adaptée à la logique de la programmation événementielle) est d'ajouter ajouter un seul gestionnaire de mouvement, présent tout le temps, et utiliser la classe "en-mouvement" pour savoir s'il y a une boite verte à déplacer.


Déplacer

15.6 Correction

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

$('.deplacer').mousedown(function(event)
{
console.log("Le bouton de la souris a été appuyé sur la boite.");
// Seulement le bouton gauche de la souris
if(event.which!==1){return;}
// Éviter de sélectionner texte si la souris bouge pendant le click
event.preventDefault();
var boite=$(this);
$('.en-mouvement').removeClass('en-mouvement');
boite.addClass('en-mouvement');
});

$('html').mouseup(function(e)
{
console.log("Le bouton de la souris a été relaché.");
$('.en-mouvement').removeClass('en-mouvement');
});

// On suit les mouvements sur toute la page.
// Si on suivait uniquement à l'intérieur de la boite un
// grand mouvement de la souris pourrait faire sortir le pointeur de la boite et
// on "perdrait" la boite.
$('html').mousemove(function(event)
{
console.log("La souris à bougé dans la page");
var boite=$('.en-mouvement');
// Si actuellement aucune boite n'est en mouvement, ignorer cet appel.
if(boite.length===0){return;}
var pos={left:event.pageX,
top: event.pageY};
boite.offset(pos);
});

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

Déplacer

15.7 Troisième étape : calculer la position de la boite

Quand l'utilisateur enfonce le bouton (1), on doit aussi enregistrer la position de la souris et de la boite verte pour pouvoir, plus tard, lors du mouvement (2), calculer la nouvelle position de la boite.

Pour avoir l'impression de "déplacer" la boite,  la position de la souris à l'intérieur de la boite ("inter." sur le schéma) doit rester la même.



Déplacer

15.8 Correction: deplacer.js

deplacer.js

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
var posDepartSouris;
var posDepartBoite;
$('.deplacer').mousedown(function(event)
{
console.log("Le bouton de la souris a été appuyé sur la boite.");
// Seulement le bouton gauche de la souris
if(event.which!==1){return;}
// Éviter de sélectionner texte si la souris bouge pendant le click
event.preventDefault();
var boite=$(this);
$('.en-mouvement').removeClass('en-mouvement');
boite.addClass('en-mouvement');
// Se souvenir de la position de départ
posDepartSouris={left:event.pageX,
top: event.pageY};
posDepartBoite =boite.offset();
});

$('html').mouseup(function(e)
{
console.log("Le bouton de la souris a été relaché.");
$('.en-mouvement').removeClass('en-mouvement');
});

// On suit les mouvements sur toute la page.
// Si on suivait uniquement à l'intérieur de la boite un
// grand mouvement de la souris pourrait faire sortir le pointeur de la boite et
// on "perdrait" la boite.
$('html').mousemove(function(event)
{
console.log("La souris à bougé dans la page");
var boite=$('.en-mouvement');
if(boite.length===0){return;}
var pos={left:event.pageX,
top: event.pageY};
pos.top -=posDepartSouris.top;
pos.left-=posDepartSouris.left;
pos.top +=posDepartBoite.top;
pos.left+=posDepartBoite.left;
boite.offset(pos);
});

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

16. Diaporama : extension

16.1 Diaporama : extension

Extension de l'exercice du TP-3 « diaporama »

On veut afficher 4 points indiquant sur quelle image on se trouve.
L'utilisateur peut cliquer sur ces points.

Vous pouvez modifier le HTML, le CSS et le JS.

Diaporama : extension

16.2 Correction

diapos.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>diapos</title>
<link type="text/css" rel="stylesheet" href="diapos.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="diapos.js"></script>
</head>
<body>
<!--------------------->
<div id="dia">
<div id="dia-images">
<img src="http://moodle.iutv.univ-paris13.fr/img/js/montagne-small.jpg" />
<img src="http://moodle.iutv.univ-paris13.fr/img/js/oiseau-small.jpg" />
<img src="http://moodle.iutv.univ-paris13.fr/img/js/escargot-small.jpg" />
<img src="http://moodle.iutv.univ-paris13.fr/img/js/marmotte-small.jpg" />
</div>
<div id="dia-fleches">
<span id="dia-gauche">&lt;</span>
<span id="dia-droite">&gt;</span>
</div>
<ul id="dia-points">
<li> </li>
<li> </li>
<li> </li>
<li> </li>
</ul>
</div>
<!--------------------->
</body>
</html>

diapos.css

/* Le cadre principal. */
#dia
{
/* On le restreint exactement à la taille d'une seule image. */
width: 600px;
height: 450px;
/* Tout ce qui déborde est caché. Donc, une seule image n'est visible. */
overflow: hidden;
/* Ceci sert uniquement pour créer un containing block */
/* qui permet de positionner les flêches avec position: absolute */
position: relative;
}

/* Un div très très large */
/* Il contient toutes les images disposées horizontalement */
/* Il déborde de son parent */
#dia-images
{
width: 10000px;
/* Trés important: c'est ce qui permet de décaler ce div en JS avec "left: ...px;" */
position: relative;
/* Eviter les petits espaces entre les images */
font-size: 0;
/* initialisation à 0 (défaut "auto") : nécessaire sur Chrome */
left: 0;
}

/* Commun aux deux flêches */
#dia-fleches span
{
position: absolute;
top: 200px;
font-size: 30px;
font-family: sans;
background-color: rgba(0,0,0,.4);
color: #bbb;
padding: .1em;
/* Le pointeur de la souris */
cursor: pointer;
}
#dia-gauche
{
left: 0;
}
#dia-droite
{
right: 0;
}
#dia-fleches span:hover
{
color: #fff;
}

#dia-points
{
margin: 0;
padding: 0;
position: absolute;
bottom: 20px;
left: 265px;
}

#dia-points li
{
display: inline-block;
width: 11px;
height: 11px;
border: 1px solid black;
border-radius: 11px;
margin-right: 5px;
cursor: pointer;
box-shadow: 0 0 1px rgba(255,255,255,.2);
}

#dia-points li:hover
{
background-color: white;
}

#dia-points li.courant
{
background-color: rgba(255,255,255,.5);
}

diapos.js

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

var minuteur=setInterval(function()
{
console.log("Appel par minuteurs");
var position=parseInt($('#dia-images').css('left'));
if(position%600!==0){return;}
position-=600;
if(position<-600*3){position=0;}
mettre_a_jour_points(position);
$('#dia-images').animate({left: position});
},2000);

$('#dia-fleches span').mousedown(function()
{
console.log("Le bouton de la souris a été appuyé sur une flèche");
if(minuteur!==false)
{
clearInterval(minuteur);
minuteur=false;
}
var position=parseInt($('#dia-images').css('left'));
if(position%600!==0){return;}
var flecheDroite=$(this).attr('id')==='dia-droite';
position+=(flecheDroite ? -600 : 600);
if(position<-600*3 || position>0){return;}
mettre_a_jour_points(position);
$('#dia-images').animate({left: position});
});

$('#dia-points li').mousedown(function()
{
if(minuteur!==false)
{
clearInterval(minuteur);
minuteur=false;
}
var imgN=$('#dia-points li').index(this);
var position=-600*imgN;
$('#dia-images').animate({left: position});
mettre_a_jour_points(position);
});

function mettre_a_jour_points(position)
{
if(position%600!==0){return;}
var imgN=-position/600;
$('#dia-points li').removeClass('courant');
$('#dia-points li').eq(imgN).addClass('courant');
}

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

Diaporama : extension

16.3 Morpion : extension

Le morpion sur lequel on a travaillé au TP-2 était très basique. On voudrait le compléter.
Vous pouvez changer le HTML, CSS et JS.

I'l s'agit de :

  1. Déterminer si un joueur a gagné
  2. Distinguer plusieurs phase du jeu


1. Déterminer si un joueur a gagné

Conseil : écrivez une fonction case_td(x,y) qui renvoie une liste jQuery contenant uniquement le 'td' de la case située à la position x,y

Cette fonction peut être utile pour déterminer si un joueur a gagné.

2. Distinguer plusieurs phase du jeu 

On voudrait  distinguer





Diaporama : extension

16.4 Correction


morpion-1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>morpion-1</title>
<link type="text/css" rel="stylesheet" href="morpion-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="morpion-1.js"></script>
</head>
<body>
<!--------------------->
<div id="jeu" class="phase-debut">
<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>
<div id="message-debut">
<p>Cliquez pour commencer à jouer.</p>
</div>
<div id="message-joueur">
<p>C'est à <span class="joueur-actuel"></span>.</p>
</div>
<div id="message-fin">
<p id="match-nul">Match nul.</p>
<p id="gagne">Le joueur <span class="joueur-actuel"></span> a gagné !</p>
<p><input id="recommencer" type="button" value="recommencer"/></p>
</div>
</div>
<!--------------------->
</body>
</html>


morpion-1.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;
}


#message-debut
{
display: none;
}

.phase-debut #message-debut
{
display: block;
}

.phase-fin #message-joueur
{
display: none;
}


#message-fin
{
display: none;
}


.phase-fin #message-fin
{
display: block;
}


morpion-1.js

console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
var joueur="X";
$('.joueur-actuel').text('"'+joueur+'"');

$('#morpion td').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
if($('#jeu').hasClass('phase-fin')){alert("Désolé, la partie est finie.");return;}
if($('#jeu').hasClass('phase-debut'))
{
$('#jeu').removeClass('phase-debut');
$('#jeu').addClass('phase-jeu');
}

if($(this).text()!==''){alert("Vous ne pouvez pas jouer là!");return;}
$(this).text(joueur);

var x=$(this).parent().find('td').index(this);
var y=$(this).parents('table').find('tr').index($(this).parent());
console.log(x,y);
var i;
var n;
var gagne=false;
n=0;
for(i=-2;i<=2;i++){if(case_td(x+i,y).text()===joueur){n++;}}
if(n===3){gagne=joueur;}
n=0;
for(i=-2;i<=2;i++){if(case_td(x,y+i).text()===joueur){n++;}}
if(n===3){gagne=joueur;}
n=0;
for(i=-2;i<=2;i++){if(case_td(x+i,y+i).text()===joueur){n++;}}
if(n===3){gagne=joueur;}

if(gagne===false && $('td').text().length===9){gagne='nul';}
console.log('gagne:',gagne);
if(gagne!==false)
{
$('#jeu').removeClass('phase-jeu');
$('#jeu').addClass('phase-fin');
$('#match-nul').toggle(gagne==='nul');
$('#gagne' ).toggle(gagne!=='nul');
return;
}

joueur=(joueur==='X' ? 'O' : 'X');
$('.joueur-actuel').text('"'+joueur+'"');
});

function case_td(x,y)
{
if(x<0 || y<0 || x>2 || y>2){return $();}
return $('#morpion tr').eq(y).find('td').eq(x);
}

$('#recommencer').click(function()
{
$('#morpion td').text('');
$('#jeu').removeClass('phase-fin');
$('#jeu').addClass('phase-debut');
});

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

17. Potentiomètres

17.1 Potentiomètres

Dans les pages suivantes on va écrire, ensemble, un petit programme permettant de déplacer des potentiomètres avec la souris pour déterminer une valeur.

Potentiomètres

17.2 Potentiomètre : HTML

Créez deux fichiers vides potentiometre.css et potentiometre.js

Créez le fichier poignee.png suivant :


Créez le fichier HTML suivant:

potentiometre.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>potentiometre</title>
<link type="text/css" rel="stylesheet" href="potentiometre.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="potentiometre.js"></script>
</head>
<body>
<!--------------------->
<p>
<span class="potentiometre" id="pot1">
<span></span>
<img src="poignee.png" alt=""/>
</span>
<span id="valeur-pot1" class="valeur"></span>
</p>

<p>
<span class="potentiometre" id="pot2">
<span></span>
<img src="poignee.png" alt=""/>
</span>
<span id="valeur-pot2" class="valeur"></span>
</p>
<!--------------------->
</body>
</html>

Potentiomètres

17.3 Potentiomètre : CSS

Le <span> vide dans le potentiomètre est prévu pour faire la couleur sombre à gauche de la poignée.
Pour pouvoir régler leur taille (width,height) le potentiomètre et le <span> doivent avoir "display: inline-block"

Pensez à position absolute et relative ... pour pouvoir positionner la poignée et le span.

Faites des essais en réglant la poignée et le <span> directement dans le CSS (on le fera plus tard dans le JS).

Potentiomètres

17.4 Correction: potentiomètre CSS

potentiometre.css

body
{
margin: 30px;
}

.potentiometre
{
/* Nécessaire pour pouvoir fixer width et height */
display: inline-block;
/* Créer un containing block */
/* pour pouvoir utiliser position: absolute sur le span et l'image */
position: relative;
width: 200px;
height: 5px;
border: 1px solid #aaa;
border-radius: 3px;
}

.potentiometre img
{
position: absolute;
top: -10px;
left: -12px;
}

.potentiometre span
{
/* Nécessaire pour pouvoir fixer width et height */
display: inline-block;
position: absolute;
top: 0px;
height: 5px;
background-color: #555;
border-radius: 3px;
}

.valeur
{
margin-left: 1em;
}

Potentiomètres

17.5 Potentiomètre JS


En vous inspirant de l'exercice "deplacer.js" du TP-4, écrivez le JS.

Indications :


Potentiomètres

17.6 Correction : potentiomètre JS

potentiometre.js

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

$('.potentiometre img').on('dragstart', function(event) { event.preventDefault(); });

$('.potentiometre img').mousedown(function(event)
{
console.log("Le bouton de la souris a été appuyé sur la poignée.");
// Seulement le bouton gauche de la souris
if(event.which!==1){return;}
// Éviter de sélectionner texte si la souris bouge pendant le click
event.preventDefault();
var poignee=$(this);
$('.en-mouvement').removeClass('en-mouvement');
poignee.addClass('en-mouvement');
// Se souvenir de la position de départ
posDepartSouris =event.pageX;
posDepartPoignee =poignee.offset().left;
});

$('html').mouseup(function(e)
{
console.log("Le bouton de la souris a été relaché.");
$('.en-mouvement').removeClass('en-mouvement');
});

$('html').mousemove(function(event)
{
console.log("La souris à bougé dans la page");
var poignee=$('.en-mouvement');
if(poignee.length===0){return;}
var potentiometre=poignee.parent();
var pos=event.pageX;
pos-=posDepartSouris;
pos+=posDepartPoignee;
// Bord gauche du potentiomètre par rapport à la page
var gauche=potentiometre.offset().left-12;
if(pos<gauche){pos=gauche;}
if(pos>gauche+potentiometre.width()){pos=gauche+potentiometre.width();}
poignee.offset({left: pos,
top: poignee.offset().top});
// largeur de la couleur de fond de la partie à gauche de la poignée
potentiometre.find('span').width(pos-gauche);
// Calculer la valeur du potentiometre entre 0 et 100
var valeur=Math.round(100*(pos-gauche)/potentiometre.width());
// Déterminer le id du span valeur à partir de l'id du potentiomètre
var valId='valeur-'+potentiometre.attr('id');
// Afficher la valeur
$('#'+valId).text(valeur);
});

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

18. Couleur

18.1 Couleur

Dans les pages suivantes, on va réaliser un « widget » permettant de choisir une couleur.

L'utilisateur peut bouger les potentiomètres ou bien taper directement les valeurs dans les 4 champs (rouge, vert, bleu, hex).

Couleur

18.2 Couleur : HTML et CSS

Cette fois-ci, c'est à vous d'écrire à la fois le HTML et le CSS.

Bien sur, vous pouvez réutiliser ce qui a été fait pour les potentiomètres.

Remarquez que les champs rouge, vert, bleu et hex sont des champs texte <input>



Couleur

18.3 Correction: HTML et CSS

Ceci n'est qu'une proposition de solution.
D'autres approches sont tout à fait possibles.

couleur.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>couleur</title>
<link type="text/css" rel="stylesheet" href="potentiometre.css"/>
<link type="text/css" rel="stylesheet" href="couleur.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="couleur.js"></script>
</head>
<body>
<!--------------------->
<div id="couleur">
<ul id="potentiometres">
<li>
<span class="potentiometre" id="pot-rouge">
<span></span>
<img src="poignee.png" alt=""/>
</span>
<input id="valeur-pot-rouge" class="valeur" type="text" value="0"/> rouge
</li>
<li>
<span class="potentiometre" id="pot-vert">
<span></span>
<img src="poignee.png" alt=""/>
</span>
<input id="valeur-pot-vert" class="valeur" type="text" value="0"/> vert
</li>
<li>
<span class="potentiometre" id="pot-bleu">
<span></span>
<img src="poignee.png" alt=""/>
</span>
<input id="valeur-pot-bleu" class="valeur" type="text" value="0"/> bleu
</li>
</ul>
<div id="ligne-bas">
<span id="boite-couleur"></span>
<input id="hex" type="text" value="#000000"/> hex
</div>
</div>
<!--------------------->
</body>
</html>

couleur.css

#couleur
{
width: 380px;
font-family: sans;
border: 1px solid #aaa;
box-shadow: 2px 2px 2px rgba(0,0,0,.2);
background-color: #fafafa;
padding: 10px;
padding-left: 20px;
border-radius: 3px;
overflow: hidden;
}

#potentiometres
{
list-style: none;
padding: 0;
margin-top: 0;
}

#couleur input
{
text-align: right;
margin-right: .5em;
}

#potentiometres input
{
width: 70px;
}

#boite-couleur
{
display: inline-block;
width: 200px;
height: 30px;
border: 1px solid #aaa;
background-color: black;
vertical-align: middle;
}

#hex
{
width: 70px;
font-family: mono;
margin-left: 1em;
}

#couleur input.erreur
{
color: red;
}


Couleur

18.4 Couleur : JS

Attention: cette partie est longue. Prenez votre temps. N'hésitez pas à appeler votre enseignant si vous avez des difficultés.

Vous êtes libres d'aborder cet exercice comme vous l'entendez.

Voici quelques fonctionnalités que l'on voudrait avoir:

Indications :

Pour transformer un nombre n en chaîne hexadécimale : Number(n).toString(16)
Attention: pour des nombres inférieurs à  10, cette chaîne ne fait qu'une lettre...

Pour transformer une chaîne h hexadécimale en nombre : parseInt(h,16)

Un nombre n non valide en JS a une valeur NaN (Not a Number). On peut utiliser isNan(n) pour savoir si un nombre est NaN

Si vous voyez que vous avez besoin d'une même fonctionnalité plusieurs fois, n'hésitez pas à créer une fonction.



Couleur

18.5 Correction : couleur.js

couleur.js

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

// Eviter le glisser-déposer par défaut de l'image.
$('.potentiometre img').on('dragstart', function(event) { event.preventDefault(); });

// Début de mouvement dans un potentiomètre
var posDepartSouris;
var posDepartPoignee;
$('.potentiometre img').mousedown(function(event)
{
console.log("Le bouton de la souris a été appuyé sur la poignée.");
// Seulement le bouton gauche de la souris
if(event.which!==1){return;}
// Éviter de sélectionner texte si la souris bouge pendant le click
event.preventDefault();
var poignee=$(this);
$('.en-mouvement').removeClass('en-mouvement');
poignee.addClass('en-mouvement');
// Se souvenir de la position de départ
posDepartSouris =event.pageX;
posDepartPoignee =poignee.offset().left;
});

// Fin de mouvement d'un potentiomètre
$('html').mouseup(function(e)
{
console.log("Le bouton de la souris a été relaché.");
$('.en-mouvement').removeClass('en-mouvement');
});

// Mouvement d'un potentiomètre
$('html').mousemove(function(event)
{
console.log("La souris a bougé dans la page");
var poignee=$('.en-mouvement');
if(poignee.length===0){return;}
var potentiometre=poignee.parent();
var pos=event.pageX;
pos-=posDepartSouris;
pos+=posDepartPoignee;
// Bord gauche du potentiomètre par rapport à la page
var gauche=potentiometre.offset().left-12;
if(pos<gauche){pos=gauche;}
if(pos>gauche+potentiometre.width()){pos=gauche+potentiometre.width();}
poignee.offset({left: pos,
top: poignee.offset().top});
// Largeur de la couleur de fond de la partie à gauche de la poignée
potentiometre.find('span').width(pos-gauche);
// Calculer la valeur du potentiometre entre 0 et 100
var valeur=Math.floor(255*(pos-gauche)/potentiometre.width());
// Déterminer le id du span valeur à partir de l'id du potentiomètre
var valId='valeur-'+potentiometre.attr('id');
// Afficher la valeur
$('#'+valId).val(valeur);
$('#'+valId).removeClass('erreur');
mise_a_jour_hex_et_couleur();
});

// Touche appuyée dans rouge, vert ou bleu
$('input.valeur').keyup(function(event)
{
var v=parseInt($(this).val());
// Validation
$(this).toggleClass('erreur',isNaN(v) || v<0 || v>255);
if($(this).hasClass('erreur')){return;}
mise_a_jour_position_pot($(this).parent().find('.potentiometre'));
mise_a_jour_hex_et_couleur();
});

// Touche appuyée dans hexadécimal
$('#hex').keyup(function(event)
{
var hex=$(this).val();
// Validation
$(this).toggleClass('erreur',!/^#[0-9a-f]{6}$/.test(hex));
if($(this).hasClass('erreur')){return;}
// Mettre à jour les champs texte rouge, vert et bleu
$('#valeur-pot-rouge').val(parseInt(hex.substr(1,2),16));
$('#valeur-pot-vert' ).val(parseInt(hex.substr(3,2),16));
$('#valeur-pot-bleu' ).val(parseInt(hex.substr(5,2),16));
$('.valeur').removeClass('erreur');
// Mettre à jour les 3 potentiomètres
mise_a_jour_position_pot($('#pot-rouge'));
mise_a_jour_position_pot($('#pot-vert' ));
mise_a_jour_position_pot($('#pot-bleu' ));
// Mettre à jour la couleur dans la boite
$('#boite-couleur').css('background-color',hex);
});

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

// Met à jour la position de la poignée d'un potentiometre en fonction de la valeur de l'input
function mise_a_jour_position_pot(potentiometre)
{
var poignee=potentiometre.find('img');
// Chercher l'élément input correspondat et prendre sa valeur
var v=parseInt(potentiometre.parent().find('input.valeur').val());
// Calculer la position par rapport à la page
var pos=(v/255)*potentiometre.width();
poignee.css('left',pos-12); /* 12 = largeur image / 2 */
potentiometre.find('span').width(pos);
}

// Met à jour la valeur hexadécimale et la couleur de la boite
// à partir des champs texte rouge, vert et bleu
function mise_a_jour_hex_et_couleur()
{
var hex='#';
// S'il y a une erreur sur un des 4 champs texte, ne pas mettre à jour
if($('.valeur.erreur').length){return;}
// Ajouter à la chaîne successivement rouge, vert et bleu
hex+=hex_deux_chiffres(parseInt($('#valeur-pot-rouge').val()));
hex+=hex_deux_chiffres(parseInt($('#valeur-pot-vert' ).val()));
hex+=hex_deux_chiffres(parseInt($('#valeur-pot-bleu' ).val()));
// Afficher la valeur hexadécimale
$('#hex').val(hex);
$('#hex').removeClass('erreur');
// Changer la couleur dans la boite
$('#boite-couleur').css('background-color',hex);
}

// Renvoie une chaîne hexadécimale à deux chiffres à partir d'un nombre décimal.
function hex_deux_chiffres(n)
{
var res=Number(n).toString(16);
if(res.length===1){res="0"+res;}
return res;
}

19. Fin

19.1 Fin

Merci d'avoir participé à ces TP !