Sujet 4

  1. Bienvenue au 4e sujet
  2. Révisions
    1. Déroulement JS - 2
    2. Déroulement JS - 1
    3. Déroulement JS - 3
    4. Déroulement JS - généralement
    5. Affichage fréquence
    6. Event listener
    7. Await
    8. erreur await
    9. AJAX await
    10. AJAX sans await
  3. Un chat pour chat : partie 1
    1. Rappels: Technologies client / serveur
    2. Client / serveur
    3. Configuration de la BDD
    4. API
    5. Nom
    6. Nom: simple_fetch
    7. Nom : fin
    8. Correction
    9. GET / POST
    10. GET/POST
    11. Changer nom : 1
    12. Correction
    13. Rappel : syntaxe objets
    14. Objet nom
    15. Raccourcis nom propriété
    16. Objets imbriqués
    17. await
    18. Changer nom: fin
    19. Correction
  4. Un chat pour chat : partie 2 : les messages
    1. Rafraîchir
    2. Correction
    3. Fetch messages
    4. Boucle réponses
    5. Correction
    6. Creation div
    7. Ajouter le message
    8. Correction
    9. Nom du message
    10. Fin rafraichir
    11. Correction
    12. Scroll
  5. Un chat pour chat : partie 3
    1. Envoyer un message
    2. Correction
    3. Réinitialisation
    4. Correction
    5. Rafraîchissement automatique
    6. Correction
    7. Chat à plusieurs
    8. Suite

1. Bienvenue au 4e sujet

1.1 Bienvenue au 4e sujet

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

Vous devez travailler connectés (lien « Connexion » en haut à droite de la page). Sinon, vous rencontrerez des problèmes d'avancement et vous risquez d'être comptés absent. En étant connectés vous retrouverez l'endroit où vous en étiez à la séance suivante.

2. Révisions

2.1 Révisions

Commençons par une rapide révision des notions des sujets précédents.

Révisions

2.2 Déroulement JS - 2

Comment s’appelle « 2 »

Révisions

2.3 Déroulement JS - 1

Que se passe-il dans « 1 » ?

Révisions

2.4 Déroulement JS - 3

Que se passe-il dans « 3 » ?


Révisions

2.5 Déroulement JS - généralement

En temps normal, le navigateur passe l'essentiel de son temps dans quelle partie ?
(répondez par un nombre)

Révisions

2.6 Affichage fréquence

Au maximum (par exemple, s'il y a une animation), à quelle fréquence est-ce que le navigateur rentre dans l'affichage (3) ?

Révisions

2.7 Event listener

<script>
console.log('A');
function xyz(){ console.log('B'); }
console.log('C');
document.addEventListener('click',xyz);
console.log('D');
</script>

On suppose qu'on démarre au début du script. Donnez l'ordre d’exécution.

Révisions

2.8 Await

<script type="module">
console.log('A');
await attendre(1000);
console.log('B');
</script>

La fonction attendre renvoie une promesse, qui est toujours tenue, après un certain temps.
On suppose qu'on démarre au début du script. Donnez l'ordre d’exécution.

Feedback OK:

En effet, « await » rend la main au navigateur, qui retourne à la boucle d'événements. L’exécution de ce <script> ne reprend qu'une fois que la promesse est tenue.


Feedback erreur:

Révisions

2.9 erreur await

La fonction range_ta_chambre('Tom') renvoie une promesse.
On veut utiliser await.
Que faut-il écrire, en une seule ligne, pour afficher « vilain » sur la console si la promesse n'est pas tenue ?
Vous devez utiliser await
Indice: utilisez un système de gestion d'erreurs

Révisions

2.10 AJAX await

Écrivez une requête AJAX sur http://exemple.org/abc qui met la réponse renvoyée par le serveur dans une variable appelée « r » (que vous créerez).
Utilisez « await »
Utilisez la fonction simple_fetch

Révisions

2.11 AJAX sans await

Écrivez une requête AJAX sur http://exemple.org/abc qui affiche la réponse renvoyée par le serveur dans la console.
Cette fois, n'utilisez pas « await »
Utilisez la fonction simple_fetch

3. Un chat pour chat : partie 1

3.1 Un chat pour chat : partie 1

Chatons avec un chat dans un petit chat, qu'on va construire ensemble.

Les fichiers HTML, CSS, et PHP sont fournis ci-dessous.
On va écrire le JS ensemble.

Important: si vous utilisez vscode: n'utilisez pas le serveur intégré (http://localhost:63342). Utilisez le serveur web de votre machine (http://localhost/~__user__nb).  Ce TP a besoin de cookies et ils ne semblent pas fonctionner sur le serveur vscode.

Dans ~/public_html créez les fichiers suivants:

chat.html

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Chat</title>
<link rel="stylesheet" href="chat.css" />
<script src="https://moodle.iutv.univ-paris13.fr/img/bjs2/bjs2-js-lib.js"></script>
</head>
<body>
<h1>Chat</h1>
<div id="chat">
<div id="haut">
<input id="nom" /><input id="changer-nom" type="button" value="Changer"/>
</div>
<div id="messages">
</div>
<div id="bas">
<input id="texte" type="text" /><button id="envoyer" type="button"><span></span></button>
</div>
</div>
<p id="boutons">
<input id="rafraichir" type="button" value="Rafraîchir"/>
<input id="reinitialiser" type="button" value="Réinitialiser"/>
</p>
<script src="chat.js"></script>
</body>
</html>

chat.css

body{
background: linear-gradient(45deg, rgba(255,255,255,1) 0%, rgba(149,222,237,1) 100%);
background-repeat: no-repeat;
padding: 2em;
font-family: sans;
color: #444;
background-attachment: fixed;
}

#haut{
padding: .5em;
}

#nom {
padding: .58em;
margin-right: .5em;
}

#chat{
position: relative;
background-color: white;
width: 30em;
border-radius: 10px;
box-shadow: 6px 6px 8px rgba(0,0,0,.3);
}

#chat::before {
display: block;
content: '';
background-image: url('https://moodle.iutv.univ-paris13.fr/img/bjs2/chat2.svg');
width: 200px;
height: 135px;
position: absolute;
z-index: -1;
top: -10px;
left: 140px;
animation: 20s infinite alternate animchat;
}

@keyframes animchat{
0% {
top: -10px;
}
47% {
top: -10px;
}
50% {
top: -20px;
}
53% {
top: -10px;
}
95% {
transform: rotate(0deg);
}
97% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}

#messages{
background-color: #cfc;
padding: .5em;
max-height: 15em;
min-height: 10em;
overflow-y: scroll;
}

.message{
position: relative;
left: -1em;
background-color: #f5f5f5;
border-radius: 10px;
margin: 1em 1em;
padding: .5em;
}

.message.a-moi{
left: 1em;
background-color: #cff;
margin-left: 1em;
text-align: right;
}

.nom{
position: relative;
color:#aa5;
font-size: 12px;
top: -.3em;
}

.message.a-moi .nom{
display: none;
}

#bas{
padding: .5em;
}

#texte {
padding: .4em;
font-size: 100%;
}

#envoyer{
position: relative;
top: -1px;
padding: .58em;
}
#envoyer>span {
border: solid black;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
transform: rotate(-45deg);
}
#boutons {
margin-top: 2em;
}

chat.js

// vide pour l'instant

chat.php

<?php

// ************* Initialisation

$db=connexion_bdd();
ini_set("xdebug.overload_var_dump", "off");
demarrer_session();
header('Access-Control-Allow-Origin: *');

// ************* Quelle action executer ?

switch($_GET['action'] ?? ''){
case 'messages':
messages();
break;
case 'nom':
nom();
break;
case 'changer-nom':
changer_nom();
break;
case 'envoyer':
envoyer();
break;
case 'reinitialiser':
reinitialiser();
break;
case 'test':
echo 'test ok';
break;
default:
echo 'Vous n\'avez pas specifié d\'action';
}

// ************* Les actions

function messages(){
global $db;
$req=$db->prepare("SELECT messages.*,utilisateurs.nom FROM messages,utilisateurs ".
"WHERE messages.utilisateur=utilisateurs.id ORDER BY messages.id ASC");
$req->execute();
$messages=$req->fetchAll(PDO::FETCH_ASSOC);
foreach($messages as &$message){
$message['aMoi']=$message['utilisateur']==$_SESSION['utilisateur'];
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($messages);
}

function nom(){
global $db;
$nom=get_nom();
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['nom'=>$nom]);
}

function changer_nom(){
global $db;

$req=$db->prepare("INSERT INTO messages(texte,utilisateur) VALUES(:texte,:utilisateur)");
$req->execute(['texte'=>'"'.get_nom().'" est devenu "'.$_POST['nom'].'"','utilisateur'=>3]);

$req=$db->prepare("UPDATE utilisateurs SET nom=:nom WHERE id=:id");
$req->execute(['id'=>$_SESSION['utilisateur'],'nom'=>$_POST['nom']]);

header('Content-Type: application/json; charset=utf-8');
echo json_encode('ok');
}

function envoyer(){
global $db;
$req=$db->prepare("INSERT INTO messages(texte,utilisateur) VALUES(:texte,:utilisateur)");
$req->execute(['texte'=>$_POST['texte'],'utilisateur'=>$_SESSION['utilisateur']]);
// Miaou!
if((rand()%15)===0){
$req->execute(['texte'=>rand()%2 ? 'miaou' : 'ron-ron','utilisateur'=>3]);
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode('ok');
}

function reinitialiser(){
initialiser_bdd();
header('Content-Type: application/json; charset=utf-8');
echo json_encode('ok');
}

// ************* Les autres fonctions

function creer_utilisateur($nom=false){
global $db;
$req=$db->prepare("INSERT INTO utilisateurs(nom,session) VALUES(:nom,:session)");
$req->execute(['nom'=>$nom===false ? 'anonyme' : $nom,'session'=>session_id()]);
$id=intval($db->lastInsertId());
return $id;
}

// Ouvrir la connexion avec la base de données.
// Si c'est la première fois, initialiser_bdd() est aussi appelée.
function connexion_bdd(){
global $db;
$db=new PDO('pgsql:host=aquabdd;dbname=etudiants', '__user_nb__', 'votremdp');
// Si la table messages n'existe pas encore, appeler initialiser_bdd()
$result = $db->query("SELECT 1 FROM messages LIMIT 1");
if($result===false){initialiser_bdd();}
// Afficher les messages d'erreur
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
return $db;
}

// Supprime les anciennes tables et les recrée à nouveau.
// Crée aussi quelques messages et utilisateurs.
function initialiser_bdd() {
global $db;
// Supprimer les tables si elles existent déjà
$db->exec('DROP TABLE IF EXISTS utilisateurs');
$db->exec('DROP TABLE IF EXISTS messages');

// Créer les tables

// Cette table utilisateurs a un champs "session" seulement
// pour gérer une situaiton particulière (voir demarrer_session())
$db->exec('CREATE TABLE utilisateurs(
id SERIAL PRIMARY KEY,
nom TEXT NOT NULL,
session TEXT NOT NULL
);');

$db->exec('CREATE TABLE messages(
id SERIAL PRIMARY KEY,
utilisateur INT NOT NULL,
texte TEXT NOT NULL
);');

creer_utilisateur('Joe');
creer_utilisateur('Leila');
creer_utilisateur('?');

// Remplir la table messages avec 3 messages
$req=$db->prepare("INSERT INTO messages(utilisateur, texte) VALUES(:utilisateur, :texte)");
$req->execute(['utilisateur'=>1,'texte'=>'Salut tout le monde.']);
$req->execute(['utilisateur'=>1,'texte'=>"Ya quelqu'un ?"]);
$req->execute(['utilisateur'=>2,'texte'=>'Salut.']);
}

// La session permet d'utiliser la variable $_SESSION qui est persistante entre deux appels.
// Ceci utilise un cookie de session.
// On utilise $_SESSION ici pour identifier qui est l'utilisateur actuel.
function demarrer_session(){
global $db;
session_start();

// Cas très particulier: si un utilisateur reinitialise la BDD,
// les autres utilisateurs resteront bloqués dans des sessions invalides.
// On doit donc vérifier si cet utilisateur+session existe bien encore.
if(isset($_SESSION['utilisateur'])){
$req=$db->prepare("SELECT COUNT(*) FROM utilisateurs WHERE id=:id AND session=:session");
$req->execute(['id'=>$_SESSION['utilisateur'],'session'=>session_id()]);
$n=$req->fetchColumn();
if($n==0){unset($_SESSION['utilisateur']);}
}

// Créer un utilisateur la première fois qu'un untilisateur se connecte sur cette session.
if(!isset($_SESSION['utilisateur'])){
$_SESSION['utilisateur']=creer_utilisateur();
$req=$db->prepare("UPDATE utilisateurs SET nom=:nom WHERE id=:id");
$req->execute(['id'=>$_SESSION['utilisateur'],'nom'=>'anonyme-'.$_SESSION['utilisateur']]);
}
}

function get_nom(){
global $db;
$req=$db->prepare("SELECT nom FROM utilisateurs WHERE id=:id");
$req->execute(['id'=>$_SESSION['utilisateur']]);
return $req->fetchColumn();
}

// Pour debugger: Affiche un ou plusieurs paramètres dans un fichier log.
// Il faut au préalable créer le fichier "vlog" avec les droits d'écriture.
function vlog(...$args) {
ob_start();
var_dump(...$args);
$content = ob_get_contents();
ob_end_clean();
file_put_contents('vlog','######'.date('r').': '.$content,FILE_APPEND);
}

?>

Un chat pour chat : partie 1

3.2 ¤ Rappels: Technologies client / serveur

Les interactions client/serveur peuvent devenir complexes. De nombreuses requêtes se font du navigateur au serveur. Les informations et même les logiciels couvrent l'un et l'autre. Pour ne pas se perdre, il est important de bien garder en tête où est employée chaque technologie (client ou serveur ?).
Pour le web, le terme "client" veut dire la même chose que "navigateur".

Dans le développement web on parle aussi de « frontend » pour ce qui se passe dans le navigateur et de « backend » pour ce qui se passe sur le serveur.


Un chat pour chat : partie 1

3.3 Client / serveur

Où sont principalement employées ces technologies ?

Un chat pour chat : partie 1

3.4 Configuration de la BDD

Pour fonctionner, la partie serveur (PHP) a besoin d'une base de données SQL.
Configurons la BDD.
Dans le PHP, trouvez la fonction connexion_bdd() (ATTENTION: pas l'appel de la fonction... son corps)
Modifiez-y la ligne qui contient vos identifiants:

$db=new PDO('pgsql:host=aquabdd;dbname=etudiants', '__user_nb__', 'votremdp');

Vérifiez que la page suivante n'affiche pas de message d'erreur:
(adaptez l'URL si vous avez une configuration différente)
http://localhost/~__user_nb__/chat.php?action=test

Qu'affiche cette page ?

Un chat pour chat : partie 1

3.5 ¤ API

chat.php est déjà écrit, vous n'aurez pas à le modifier.
C'est une situation classique dans laquelle on se retrouve quand on développe en « frontend »:

On développe du code JS « frontend » sur le navigateur.
On accède à un service « backend » existant déjà sur un serveur. Ce « backend » fournit une API.

L'API consiste ici, des URL suivantes:
http://localhost/~__user_nb__/chat.php?action=messages
http://localhost/~__user_nb__/chat.php?action=nom
http://localhost/~__user_nb__/chat.php?action=changer-nom
http://localhost/~__user_nb__/chat.php?action=envoyer
http://localhost/~__user_nb__/chat.php?action=reinitialiser
http://localhost/~__user_nb__/chat.php?action=test
On a déjà vu « test ». On verra comment utiliser chacune d'entre-elles.

Un chat pour chat : partie 1

3.6 Nom

Commençons par:

http://localhost/~__user_nb__/chat.php?action=nom

C'est une requête GET très simple qui fournit le nom de l'utilisateur.
Essayez de l'ouvrir dans votre navigateur.
Quel est le nom retourné ?

Un chat pour chat : partie 1

3.7 Nom: simple_fetch

http://localhost/~(votre numero utilisateur)/chat.php?action=nom

Au démarrage du JS, on voudrait aller chercher sur le serveur le nom de l'utilisateur.

Que faut-il écrire pour afficher sur la console le nom de l'utilisateur ?
- Utilisez simple_fetch
- Important: n'utilisez pas await
- Utilisez une fonction fléchée avec des accolades
- Regardez bien ce qui est retourné par le serveur. On veut afficher uniquement le nom, pas un objet.

Un chat pour chat : partie 1

3.8 Nom : fin

Dans le chat.js, cherchez le nom sur le serveur et remplissez le champ texte ayant le id « nom ».

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 1

3.9 Correction

simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});

Un chat pour chat : partie 1

3.10 ¤ GET / POST

Quand on fait une requête HTTP, on utilise une « méthode ».
La méthode par défaut est « GET ».
Une autre méthode est appelée « POST »

Les requêtes GET et POST peuvent toutes les deux contenir des informations dans l'URL
http://example.com/abc?nom=Tom
La requête POST envoie, en plus, des informations dans le corps de la requête. Ces informations n’apparaissent pas dans l'URL.

Un chat pour chat : partie 1

3.11 GET/POST

Voici une brève description des URL de l'API:

Quelle méthode faut-il utiliser pour chacune ?



Feedback erreur:

Rappel:

  • On choisit GET quand la requête peut être répétée plusieurs fois, sans effet.
    Typiquement pour chercher des informations sur le serveur.
  • On choisit POST quand la requête ne peut pas être répétée plusieurs fois.
    Typiquement pour envoyer des informations sur le serveur.


Un chat pour chat : partie 1

3.12 Changer nom : 1

Quand l'utilisateur clique sur « Changer », créez une variable appelée « nom » contenant le nom qui se trouve dans le champs texte. Puis affichez cette variable nom dans la console.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 1

3.13 Correction

document.getElementById('changer-nom').addEventListener('click',()=>{
const nom=document.getElementById('nom').value;
console.log(nom);
});

Un chat pour chat : partie 1

3.14 Rappel : syntaxe objets

Rappel : syntaxe objets

En JS, on crée un objet avec des accolades:

{
propriete1: valeur1,
propriete2: valeur2,
}

On peut, bien sur, l'écrire sur une ligne:

{propriete1: valeur1,propriete2: valeur2,}
Écrivez un objet qui contient la propriété parfum associée à la valeur "chocolat" et la propriété prix associée au nombre 2

Un chat pour chat : partie 1

3.15 Objet nom

On suppose qu'on a déjà:

  const nom=document.getElementById('nom').value;
Écrivez un objet ayant une propriété nom associée à la valeur contenue dans la variable nom

Un chat pour chat : partie 1

3.16 ¤ Raccourcis nom propriété

En JS on crée beaucoup d'objets et on se retrouve souvent dans la situation suivante:

let nom='Tom';
let o={ nom: nom };

ou bien

let a='Joe', b=123;
let o={a:a,b:b};

Quand la valeur de la propriété est une variable ayant le même nom que la propriété, le JS permet de raccourcir :-)

{a:a,b:b} se racourcit en {a,b}

Comment se raccourcit {nom:nom} ?

Un chat pour chat : partie 1

3.17 Objets imbriqués

Objets imbriqués

Bien sur, la valeur d'une propriété peut elle même être un objet. 

let joe={ nom:'joe', domicile: {ville:'Villetaneuse',adresse:'123 rue Abc'} }

Écrivez un objet avec une propriété « post » dont la valeur est un objet.
Ce deuxième objet a une propriété « nom » dont la valeur est une variable « nom ».
Raccourcissez si c'est possible.

Un chat pour chat : partie 1

3.18 await

Dans votre code, après le console.log(nom) on va vouloir faire une requête simple_fetch avec await.
Que faut-il écrire à la place de XYZ pour avoir le droit de le faire ?

document.getElementById('changer-nom').addEventListener('click',XYZ ()=>{
const nom=document.getElementById('nom').value;
console.log(nom);
});

Un chat pour chat : partie 1

3.19 Changer nom: fin

simple_fetch fonctionne par défaut avec GET.
On peut lui passer en deuxième paramètre un objet contenant une propriété appelée « post » et ayant comme valeur un objet.
simple_fetch fera alors une requête POST et enverra dans cette requête les informations de cet autre objet au serveur.
Par exemple, ceci envoie 'xyz associée à 'abc' et 123 associé à 'def' :

simple_fetch('https://exemple.com/abc',{ post: { abc: 'xyz', 'def': 123 } });

Dans notre cas, on veut envoyer la propriété « nom » associée à la variable nom à l'URL:
http://localhost/~__user_nb__/chat.php?action=changer-nom

document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
console.log(nom);
XYZ
});
Que faut-il écrire à la place de XYZ pour changer le nom sur le serveur (en utilisant await) ?

Inspirez vous de la réponse précédente.
Essayez dans votre code, avant de répondre.

Un chat pour chat : partie 1

3.20 Correction

document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
});

4. Un chat pour chat : partie 2 : les messages

4.1 Un chat pour chat : partie 2 : les messages

Un chat sans messages, c'est triste.

Dans les pages suivantes, on va aller chercher les messages et les afficher.

Un chat pour chat : partie 2 : les messages

4.2 Rafraîchir

Dans cette partie, on va se contenter de chercher les messages du chat quand l'utilisateur clique sur le bouton rafraîchir.

Quand l'utilisateur clique sur le bouton « Rafraîchir », appelez une fonction (pas anonyme) appelée « rafraichir ».
Créez cette fonction et affichez-y « rafraîchir » dans la console. Prévoyez qu'on utilisera await dans cette fonction.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 2 : les messages

4.3 Correction

document.getElementById('rafraichir').addEventListener('click',rafraichir);

async function rafraichir(){
console.log('rafraichir');
}

Un chat pour chat : partie 2 : les messages

4.4 Fetch messages

L'URL pour chercher les messages est:
http://localhost/~__user_nb__/chat.php?action=messages
Elle renvoie un tableau JSON avec tous les messages du chat, qui est converti par simple_fetch en tableau d'objets.

Que faut-il écrire pour chercher les messages sur le serveur, créer une variable « reponse » et y mettre la liste des messages cherchés ?
Utilisez await.
Essayez dans votre code (dans la fonction rafraîchir) avant de répondre.
(Votre réponse ne de doit pas contenir la fonction rafraîchir, juste la ligne qui permet de chercher et de créer la variable « reponse » )

Un chat pour chat : partie 2 : les messages

4.5 Boucle réponses

Au tout début du fichier créez le raccourci pour le div « messages »:

const messages=document.getElementById('messages');

La première chose qu'on doit faire avant d'afficher les messages reçus, est d'effacer ceux qui seraient déjà affichés.
(Ce n'est pas utile la première fois, mais ensuite si.)

Après simple_fetch() , ajoutez:

messages.innerHTML='';

« reponse » est un tableau JS. Pour afficher ces messages, il faut parcourir le tableau « reponse » et créer le HTML correspondant à chaque message.

Commençons par parcourir le tableau avec une boucle.
Écrivez la boucle pour parcourir « reponse » et affichez chacun des messages dans la console.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 2 : les messages

4.6 Correction

async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
console.log(reponse[i]);
}
}

Un chat pour chat : partie 2 : les messages

4.7 Creation div

La structure qu'on veut créer pour chaque message est la suivante:

<div class="message">
<div class="nom"></div>
<div class="texte"></div>
</div>

On va créer le div à la main, puis le remplir en utilisant innerHTML.
Ensuite on remplira le nom et le texte.

Que faut-il écrire pour créer un élément div et le mettre dans une nouvelle variable appelée « message » ?


Un chat pour chat : partie 2 : les messages

4.8 Ajouter le message

En vous inspirant de la doc ci-dessus:
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 2 : les messages

4.9 Correction

async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
messages.append(message);
}
}

Un chat pour chat : partie 2 : les messages

4.10 Nom du message

Avant le append, utilisez innerHTML pour créer facilement les deux div:

async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
messages.append(message);
}
}

Maintenant qu'on a les deux divs, il va falloir écrire le nom et le texte dedans.
Commençons par le nom.
Normalement on utilise querySelector sur document: document.querySelector
Mais, si on part du document, on ne pourra pas trouver le div nom.
Cependant, querySelector peut s'appliquer sur n'importe quel élément, notamment celui qui se trouve dans la variable « message ». Il permet de démarrer la recherche sur l'élément en question.
Utilisez querySelector pour trouver le div nom dans message et écrivez dans son textContent le nom contenu dans la réponse.

Un chat pour chat : partie 2 : les messages

4.11 Fin rafraichir

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 2 : les messages

4.12 Correction

const messages=document.getElementById('messages');

simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});

document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
rafraichir();
});

document.getElementById('rafraichir').addEventListener('click',rafraichir);

async function rafraichir(){
const reponse=await simple_fetch('chat.php?action=messages');
console.log('rafraichir:',reponse);
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
if(reponse[i].aMoi){message.classList.add('a-moi');}
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
message.querySelector('.nom' ).textContent=reponse[i].nom;
message.querySelector('.texte').textContent=reponse[i].texte;
messages.append(message);
}
}

Un chat pour chat : partie 2 : les messages

4.13 Scroll

On voudrait qu'à chaque rafraîchissement, le dernier message soit affiché en bas.
Pour ça, on va utiliser la propriété messages.scrollTop.

C'est un peu compliqué. Voici les modifications à faire:

const messages=document.getElementById('messages');

simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});

document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
rafraichir(true);
});

document.getElementById('rafraichir').addEventListener('click',rafraichir);

async function rafraichir(forcerScroll=false){
const reponse=await simple_fetch('chat.php?action=messages');
console.log('rafraichir:',reponse);
const scrollEstEnBas=Math.abs(messages.scrollHeight-messages.clientHeight-messages.scrollTop) < 10;
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
if(reponse[i].aMoi){message.classList.add('a-moi');}
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
message.querySelector('.nom' ).textContent=reponse[i].nom;
message.querySelector('.texte').textContent=reponse[i].texte;
messages.append(message);
}

if(scrollEstEnBas || forcerScroll){scroller_en_bas();}
}

function scroller_en_bas(){
setTimeout(()=>messages.scroll({top:100000,left:0,behavior:'smooth'}),0);
}



5. Un chat pour chat : partie 3

5.1 Un chat pour chat : partie 3

Ca y est ! Notre chat a des messages.
Mais on ne peut pas encore en envoyer...

Un chat pour chat : partie 3

5.2 Envoyer un message

En vous inspirant de ce qui a été fait avant, envoyez le message tapé dans le champs texte ayant l'id « texte » quand l'utilisateur appuie sur la flèche.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 3

5.3 Correction

document.getElementById('envoyer').addEventListener('click',async ()=>{
const texte=document.getElementById('texte');
if(texte.value===''){return;}
await simple_fetch('chat.php?action=envoyer',{post:{texte:texte.value}});
texte.value='';
rafraichir(true);
});

Un chat pour chat : partie 3

5.4 Réinitialisation

Réinitialisation
On veut pouvoir tout remettre à zéro pour pouvoir débugger.

En vous inspirant de ce qui a été fait avant, appelez l'API « reinitialiser » quand l'utilisateur appuie sur le bouton « Réinitialiser ».

L'URL est :
http://localhost/~__user_nb__/chat.php?action=reinitialiser
Elle prend un paramètre POST vide: mettez juste un objet vide {}
Après la requête, rechargez la page avec:

  window.location.reload();
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Un chat pour chat : partie 3

5.5 Correction

document.getElementById('reinitialiser').addEventListener('click',async ()=>{
await simple_fetch('chat.php?action=reinitialiser',{post:{}});
window.location.reload();
});

Un chat pour chat : partie 3

5.6 Rafraîchissement automatique

Utilisez setInterval pour appeler rafraichir() toutes les secondes.

Un chat pour chat : partie 3

5.7 Correction

const messages=document.getElementById('messages');

simple_fetch('chat.php?action=nom').then((reponse)=>{
const nom=document.getElementById('nom');
nom.value=reponse.nom;
});

document.getElementById('changer-nom').addEventListener('click',async ()=>{
const nom=document.getElementById('nom').value;
await simple_fetch('chat.php?action=changer-nom',{post:{nom}});
rafraichir(true);
});

document.getElementById('reinitialiser').addEventListener('click',async ()=>{
await simple_fetch('chat.php?action=reinitialiser',{post:{}});
window.location.reload();
});

document.getElementById('rafraichir').addEventListener('click',rafraichir);
setInterval(rafraichir,1000);

document.getElementById('envoyer').addEventListener('click',async ()=>{
const texte=document.getElementById('texte');
if(texte.value===''){return;}
await simple_fetch('chat.php?action=envoyer',{post:{texte:texte.value}});
texte.value='';
rafraichir(true);
});

async function rafraichir(forcerScroll=false){
const reponse=await simple_fetch('chat.php?action=messages');
console.log('rafraichir:',reponse);
const scrollEstEnBas=Math.abs(messages.scrollHeight-messages.clientHeight-messages.scrollTop) < 10;
messages.innerHTML='';
for(let i=0;i<reponse.length;i++){
const message=document.createElement('div');
message.className='message';
if(reponse[i].aMoi){message.classList.add('a-moi');}
message.innerHTML='<div class="nom"></div><div class="texte"></div>';
message.querySelector('.nom' ).textContent=reponse[i].nom;
message.querySelector('.texte').textContent=reponse[i].texte;
messages.append(message);
}

if(scrollEstEnBas || forcerScroll){scroller_en_bas();}
}

function scroller_en_bas(){
setTimeout(()=>messages.scroll({top:100000,left:0,behavior:'smooth'}),0);
}

Un chat pour chat : partie 3

5.8 Chat à plusieurs

Un chat tout seul s'ennuie...

Vous pouvez créer un autre utilisateur en utilisant une fenêtre de navigation privée (Ctrl+Maj+p sur Firefox).

Vous pouvez aussi faire fonctionner votre programme à partir de deux machines de la salle TP.
Il s'agit d'utiliser le code d'une seule personne. Il suffit donc qu'un des deux ait écrit le code (ici ces sera "vous"), l'autre personne (votre "voisin") ne fait que se connecter sur votre site.
  • Obtenez votre adresse IP locale en tapant la commande « ip a » dans un terminal. Ce sera une adresse en 192.168.....
  • Vérifiez que tout votre code HTML, JS, CSS, PHP est bien dans ~/public_html
  • Vérifiez que vous pouvez bien y accéder par http://(votre ip)/~__user_nb__/chat.html
  • Dans votre code JS, pour les requêtes AJAX, remplacez localhost par votre adresse IP.
  • Demandez à votre voisin de se connecter à http://(votre ip)/~__user_nb__/chat.html

Un chat pour chat : partie 3

5.9 Suite

Uniquement si vous êtes en avance:

Ajoutez un bouton, visible uniquement un message qu'on a soi même écrit, permettant de l’effacer.

Étudiez le code PHP.

Ajoutez les code nécessaire en JS et PHP pour que ça marche (que le message soit effectivement effacé sur le serveur).