Partie 1: Application Pictionnary

De $1

Version de 02:09, 2 Mai 2024

cette version.

Revenir à liste des archives.

Voir la version actuelle

Objectifs

Nous allons survoler les bases du développement d'une application HTML5, et développer une application similaire à l'application Draw Something, compatible avec le web mobile.

Cette partie va durer 3 séances de 3h. L'application complète sera rendue et vaudra 20% de la note finale du cours.

Concepts abordés:

  • Formulaire d'inscription/connexion HTML5,
  • adaptation au web mobile,
  • élément canvas
  • exportation d'un canvas en image
  • fonctionnalité de partage Twitter, Facebook
  • format d'échange JSON

Technologies utilisées:

PHP, MySQL, HTML5, CSS3, javascript

Prenez l'habitude d'utiliser les outils de développement de votre navigateur pour étudier le DOM, les échanges réseau, le javascript, le CSS, ...

Mise en route

Discussion:  Qu'est-ce que le HTML 5 ? 

On va aborder un ensemble de concepts nouveau dans le HTML5. 

A faire: Survoler la liste sur le site http://html5test.com/

Dans la partie 1 du cours on va se concentrer sur:

  • Parsing Rules
  • Elements
    • Embedding custom non-visible data
    • Section elements 
    • Text level elements: download, ping, mark, ruby
    • Interactive Elements: Details, Summary
  • Forms
    • nouveaux champs de formulaire, validation, ...
  • 2D graphics
    • canvas
    • Image export format
  • Storage
    • IndexedDB
  • Other
    • JSON encoding and decoding

Discussion:  Quels autres points de la liste connaissez vous ? vous intriguent ?

 

Soyez curieux, demandez, ou cherchez sur le net.

Parsing Rules, headers, balises meta

A faire: Validez chacun de ces documents html dans le validateur du w3c: http://validator.w3.org/#validate_by_input

Corrigez les erreurs.

Prenez l'habitude de valider vos documents HTML.

HTML 4.01

<!doctype html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="fr">
   <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <title>My first HTML document</title>
      <meta name="description" content="Exemple de description">
      <link rel="stylesheet" type="text/css" href="monStyle.css">
      <script type="text/javascript" src="monSript.js"></script>
   </head>
   <body>
      <div>...</div>
   </body>
</html>
 
 
HTML5
<!doctype html>
<html lang="fr">
   <head>
      <meta charset="UTF-8">
      <title>My first HTML document</title>
      <meta name="description" content="Exemple de description">
      <link rel="stylesheet" href="monStyle.css"/>
      <script src="monSript.js"></script>
   </head>
   <body>
      <div>...</div>
   </body>
</html>
 
Discussion: Commentaires ? Des différences importantes ? 
 
Cours: Dans le document à l'url http://www.slow-lab.com/guide-balises-meta.php, lisez les sections suivantes: 
  • Tout jusqu'à: Les balises Meta de partage Facebook
  • Les balises Meta Language et Content-language
  • À Quoi Ressemble Un <Head> Propre?
 
Ne vous attardez pas trop dans les détails, en particulier pour les balises meta de partage Facebook: on y reviendra en détail plus tard...
 
Discussion: Commentaires ? Une idée de ce que peut bien être le web sémantique ? 

Elements

A faire: Téléchargez le projet demoHTML5 ci-joint. Exécutez et étudier les sources de chaque fichier HTML.

1_customNonVisibleData:

Etudiez le document à l'url http://www.alsacreations.com/article/lire/1397-html5-attribut-data-dataset.html 

2_SectionElements:

Etudiez le document à l'url http://www.alsacreations.com/article/lire/1376-html5-section-article-nav-header-footer-aside.html 

3_textLevelElements:

Comprenez l'utilité:

  • de l'élément mark
  • des attributs download et ping
  • des éléments ruby 

4_InteractiveElements:

Etudiez le document à l'url http://www.alsacreations.com/article...s-summary.html  

TP Formulaires

On va créer un projet PHP avec base de données MySQL pour faire une page d'inscription, et une de connexion pour notre site.

Cours: Pour les formulaires HTML5, une introduction peut être lue à la page suivante: http://standardista.com/forms/. Vous vous inspirerez ensuite des documents suivants

Etudiez l'exemple exemple_inscription.html

page inscription.html

Le formulaire d'inscription doit comporter les champs suivants:

adresse email  type email, obligatoire, a le focus par défaut
mot de passe  type password, obligatoire, entre 4 et 8 caractères alphanumériques (validation avec l'attribut pattern)
confirmation du mot de passe  type password, obligatoire, doit être égal au premier champs mot de passe (validation avec l'api validation)
nom  type text, optionnel
prénom  type text, obligatoire
téléphone  type tel, optionnel
site web  type url, optionnel
sexe  type radio button, optionnel
date de naissance  type date, obligatoire
age  type number, disabled, doit être calculé lorsque la date de naissance change
ville  type text, optionnel
taille  type range, de 0m à 2.50m, avec un pas de 0.01m.
couleur préférée  type color, noir par défaut (attribut value)
photo de profil  type file. 

 

Prenez comme base le code html ci-dessous:

<!DOCTYPE html>
<html>
<head>
    <meta charset=utf-8 />
    <title>Pictionnary - Inscription</title>
</head>
<body>

<form class="inscription" action="req_inscription.php" method="post" name="inscription">
    <ul>
        <li>
            <h2>Inscrivez-vous</h2>
            <span class="required_notification">Les champs obligatoires sont indiqués par *</span>
        </li>
        <li>
            <label for="email">E-mail :</label>
            <input type="email" name="email" id="email" autofocus required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"/>
            <span class="form_hint">Format attendu "name@something.com"</span>
        </li>
        <li>
            <label for="prenom">Prénom :</label>
            <input type="text" name="prenom" id="prenom" required placeholder="votre prénom..."/>
        </li>
        <li>
            <label for="mdp1">Mot de passe :</label>
            <input type="password" name="password" id="mdp1" required pattern="\w{6,8}" onkeyup="validateMdp2()" title = "Le mot de passe doit contenir de 6 à 8 caractères alphanumériques." placeholder="votre mot de passe">
            <span class="form_hint">De 6 à 8 caractères alphanumériques.</span>
        </li>
        <li>
            <label for="mdp2">Confirmez mot de passe :</label>
            <input type="password" id="mdp2" required onkeyup="validateMdp2()" placeholder="réécrivez votre mot de passe">
            <span class="form_hint">Les mots de passes doivent être égaux.</span>
            <script>
                validateMdp2 = function(e) {
                    if (document.getElementById('mdp1').checkValidity() && document.getElementById('mdp2').value == document.getElementById('mdp1').value) {
                        document.getElementById('mdp2').setCustomValidity('');
                    } else {
                        document.getElementById('mdp2').setCustomValidity('Les mots de passes doivent être égaux.');
                    }
                }
            </script>
        </li>
        <li>
            <label for="nom">Nom :</label>
            <input type="text" name="nom" id="nom" required placeholder="votre nom..."/>
        </li>
        <li>
            <input type="submit" value="Soumettre Formulaire">
        </li>
    </ul>
</form>
</body>
</html>

Comme vous pouvez le voir, 

  • Chaque champs est un item d'une liste
  • Le premier élément de la liste contient le titre du formlaire et une indication pour les champs obligatoires
  • Chaque champs est précédé d'un élément label associé (lorsqu'on clique sur un label, le champs associé reçoit le focus), et peut être suivi d'une indication sur le format attendu.
  • On utilise à bonne escient les attributs required, placeholder, pattern.
  • L'attribut pattern contient une expression régulière javascript, c.f., https://developer.mozilla.org/fr/docs/JavaScript/Guide/Expressions_r%C3%A9guli%C3%A8res
  • La vérification de l'égalité des mots de passe est effectuée directement avec l'API validation, lors d'un keyup.

Lorsqu'on clique sur "confirmez mot de passe", c'est le premier champs mot de passe qui reçoit le focus. corrigez celà. Puis, complétez le formulaire.

Pour l'âge: on veut parser la valeur du champs birthdate en date, comparer avec la date d'aujourd'hui, et récupérer l'année. vous pouvez utiliser l'attribut valueAsDate ainsi:

<li>
            <label for="birthdate">Date de naissance:</label>
            <input type="date" name="birthdate" id="birthdate" placeholder="JJ/MM/AAAA" required onchange="try{computeAge()}catch(e){document.getElementById('age').value = ''}"/>
            <script>
                computeAge = function(e) {
                    var elapsed = Date.now()-Date.parse(document.getElementById("birthdate").valueAsDate);
                    document.getElementById("age").value = new Date(elapsed).getYear()-70;
                }
            </script>
            <span class="form_hint">Format attendu "JJ/MM/AAAA"</span>
        </li>
        <li>
            <label for="age">Age:</label>
            <input type="number" name="age" id="age" disabled/>
        </li>

Pour la photo de profil, on utilise l'API File, un canvas pour redimensionner et pré-visualiser l'image, et un champs caché pour stocker l'image sous la forme d'une data url. Utilisez et étudiez le code suivant:

<li>
            <label for="profilepicfile">Photo de profil:</label>
            <input type="file" id="profilepicfile" onchange="loadProfilePic(this)"/>
            <span class="form_hint">Choisissez une image.</span>
            <input type="hidden" name="profilepic" id="profilepic"/>
            <canvas id="preview" width="0" height="0"></canvas>
            <script>
                loadProfilePic = function (e) {
                    // on récupère le canvas où on affichera l'image
                    var canvas = document.getElementById("preview");
                    var ctx = canvas.getContext("2d");
                    ctx.clear;
                    canvas.width=0;
                    canvas.height=0;
                    //récupérer le fichier
                    var file = document.getElementById("profilepicfile").files[0];
                    var img = document.createElement("img");
                    var reader = new FileReader();
                    // on prépare le callback appelé lorsque l'image sera chargée
                    reader.onload = function(e) {
                        if (!file.type.match(/image.*/)) {
                            // le fichier choisi n'est pas une image
                            document.getElementById("profilepicfile").setCustomValidity("Il faut télécharger une image.");
                            document.getElementById("profilepicfile").value = "";
                            console.error("Il faut télécharger une image.");                        }
                        else {
                            img.src = e.target.result;
                            document.getElementById("profilepicfile").setCustomValidity("");

                            // on dessine l'image dans le canvas à la position 0,0,
                            // et avec une largeur et hauteur maximale de 96
                            var MAX_WIDTH = 96;
                            var MAX_HEIGHT = 96;
                            var width = img.width;
                            var height = img.height;
                            if (width > height) {
                                if (width > MAX_WIDTH) {
                                    height *= MAX_WIDTH / width;
                                    width = MAX_WIDTH;
                                }
                            } else {
                                if (height > MAX_HEIGHT) {
                                    width *= MAX_HEIGHT / height;
                                    height = MAX_HEIGHT;
                                }
                            }
                            canvas.width = width;
                            canvas.height = height;
                            ctx.drawImage(img, 0, 0, width, height);
                            var dataurl = canvas.toDataURL("image/png");
                            // on donne finalement une data url comme valeur au champs profilepic
                            document.getElementById("profilepic").value = dataurl;
                        };
                    }
                    // on charge l'image
                    reader.readAsDataURL(file);
                }
            </script>
        </li>

 

Style CSS3

(inspiré de http://webdesign.tutsplus.com/tutorials/site-elements/bring-your-forms-up-to-date-with-css3-and-html5-validation/)

On va modifier le fichier styles.css qui contient le style pour les ordinateurs seulement (media="screen"). Ajoutez la ligne suivante dans le header: 

<link rel="stylesheet" media="screen" href="styles.css" >

Etudiez la feuille de style en CSS3, renseignez-vous sur les sélecteurs :focus, :valid, :invalid, les transitions,  

La base de données 

Avec PhpMyAdmin,

  • Créez une base pictionnary avec l'encodate utf-8-general_ci
  • Dans verifier les privileges, créez un utilisateur, nom test, client local, mot de passe test, donner tous les privilèges sur la base pictionnary, donner aucun privilège global. C'est avec cet utilisateur qu'on se connectera à la base de données en php. en SQL:
CREATE USER 'test'@'localhost' IDENTIFIED BY  'test';
GRANT USAGE ON * . * TO  'test'@'localhost' IDENTIFIED BY  'test';
GRANT ALL PRIVILEGES ON  `pictionnary` . * TO  'test'@'localhost';

Mainteant dans PHPStorm, connectez-vous à la base de données pictionnary avec l'utilisateur test et le mot de passe test:

view -> tool windows -> database, puis ajouter datasource mysql, jdbc:mysql://localhost:3306/pictionnary, télécharger le driver si besoin.
Si votre pare-feu s'alarme, débloquez les connexions.
  • créez une table USERS avec la signature suivante (Soit dans la console mysql, soit dans phpmyadmin, soit maintenant dans PHPStorm)
DROP TABLE IF EXISTS `users`;
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL,
`email` varchar(65) NOT NULL,
`password` varchar(65) NOT NULL,
`nom` varchar(65) DEFAULT NULL,
`prenom` varchar(65) DEFAULT NULL,
`tel` varchar(16) DEFAULT NULL,
`website` varchar(65) DEFAULT NULL,
`sexe` char(1) DEFAULT NULL,
`birthdate` date NOT NULL,
`ville` varchar(65) DEFAULT NULL,
`taille` smallint(6) DEFAULT NULL,
`couleur` char(6) DEFAULT '000000',
`profilepic` blob NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

 


Page req_inscription.php

On va maintenant remplir la base lorsqu'un utilisateur rentre ses données dans le formulaire.
Pour celà on utilise soit mySQLi, soit JDO. surtout pas mySQL, c.f., http://www.php.net/manual/fr/mysqlinfo.api.choosing.php
Je propose JDO, puisqu'on s'en servirait pareil si la base était Oracle, Derby ou autre. le manuel en français est disponible ici: http://www.php.net/manual/fr/intro.pdo.php

 

pour le champs de formulaire inscription:

Formulaire de connexion

Le formulaire de connexion devra comporter les champs suivants:

ladresse email  type email, obligatoire, a le focus par défaut
 
mot de passe  type password, obligatoire

 

Créez une base de données MySQL et configurez votre projet dans PHPStorm pour l'utiliser. Créez une table USERS, avec le code SQL suivant:

DROP

 

 

 

 

 

http://www.phpeasystep.com/phptu/6.html 

http://dmouronval.developpez.com/tut...ulaires-html5/

Si vous n'êtes pas au point sur les cookies / sessions en PHP, étudiez le document à l'URL http://www.julp.fr/articles/17-php-cookies-et-sessions.html#utilisation (sections 1 à 2.2.9)

Web Mobile

On va réfléchir aux différentes solutions possibles pour adapter note site web aux mobiles

c.f., choix du site lemonde.fr, ou feuille de style avec sélecteur user-agent. Avantages/Inconvénients ?

Activité: faire en sorte que notre formulaire s'affiche bien sur mobile. tester. 

 

https://developers.google.com/chrome...mulation?hl=fr

Canvas

quand on est loggué, on redirige vers une page paint.html, on va créer un paint interactif très simple, avec un peu de javascript. Juste des cercles de différentes tailles, et un sélecteur de couleurs avec summary/details.

 

http://miageprojet2.unice.fr/Intranet_de_Michel_Buffa/Web_2.0%2F%2FHTML5_Rabat_2012-2013
 

Stockage interne

On veut enregistrer dans le navigateur chaque évènement souris, pour pouvoir l'envoyer au serveur plus tard, et le rejouer ensuite sur un autre appareil.

On étudie les solutions de stockage interne dans le navigateur, leur adaptation par les navigateurs existants, 

JSON

 

On se met d'accord sur un format JSON pour représenter ces dessins.

On ajoute un formulaire avec un bouton de soumission, qui envoie une requète POST à une page soumission.php

 

 

 

On stocke ces informations dans la base de données

 

Travail à rendre juste avant la séance n°5

 

 

 

Créer une autre page pour rejouer le dessin, avec un formulaire simple pour répondre à la question. 

Comment éviter que celui qui doit deviner puisse tricher (avec un md5 ?)

Transformer en jeu, et s'assurer que le site soit adapté pour mobile.