Mots-clé : jquery

IUT alternants : projet Django / Python à rendre le 12 février minuit au plus tard

A rendre le dimanche 12 février 2023 minuit au plus tard


Projet individuel


Comment le rendre

Faites un fichier README.txt et déposez-le ici
Dans le fichier README.txt, précisez :

  • le sujet choisi
  • l’adresse de votre site
  • un nom d’utilisateur
  • un mot de passe
  • (et plusieurs nom/mot de passe, s’il y a plusieurs niveaux de droits (administrateur/visiteur etc.))
  • si vous avez utilisé des librairies spécifiques que je vous ai autorisées, merci de le re-préciser

Sujet

Ce que vous voulez tant que c’est dans le cadre de ce que l’on a vu. Vous avez tout le Web comme inspiration !
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !
Si vous gérez des profils différents (admin / user ou autre), donnez moi les noms et mots de passe de différents profils !


Fonctionnalités obligatoires

  • Nouveaux modèles
  • Nouvelles relations à mettre en oeuvre : ForeignKey, ManyToMany, OneToOne
  • Au moins un formulaire
  • Connexion + déconnexion (vu en cours)
  • Visualisation de tout dans l’interface d’administration

Sujets possibles

  1. Site de partage de photos
  2. Site de cocktails (cf ci-dessus)
  3. e-rated : site d’appréciations (selon des sujets, à définir)
  4. Ask-a-question : site où l’on pose des questions sur des sujets divers, et des gens répondent
  5. Write-a-book-together : site où l’on se connecte et où on peut écrire un livre à plusieurs
  6. Wedding-couple-site : site où l’on uploade + partage des photos de mariage + livre de commandes
  7. Playing-cards-collection : site où on scanne + échange des cartes (Magic the gathering)
  8. Polls-and-surveys : site de création de sondages (= QCM, exemple très beau ici : quipoquiz)
  9. Poems-generator : faire un cadavre exquis qui génère des poèmes + possibilité pour les utilisateurs de les noter / d’ajouter des mots
  10. The-future-of-post-it : faire un carnet de choses à faire pour les utilisateurs, qui envoie des mails de rappels de ces choses à des dates données
  11. Gift-ideas : un site où l’on va faire des idées de cadeaux / suggérer des idées de cadeaux + les noter (les meilleurs ressortent en premier)
  12. Le-bon-recoin : refaire le bon coin en plus simple
  13. Suggest-crawlers : site de suggestions : on clique sur un mot, il en suggère plein d’autres avec + définitions / liens de sites pour chacuns
  14. Tv-fans : site de présentations + notes d’émissions télé
  15. Faire le jeu SokoBan vu en cours, avec la possibilité de login, enregistrement. Pour les appels JSON supplémentaires, lorsque l’utilisateur choisit un tableau, s’en souvenir (= AJAX) et lorsqu’il se reconnecte, le remettre directement. Puis enregistrer son score lorsqu’il a terminé un niveau + montrer les meilleurs scores.

Pour les sujets qui suivent, ils sont possibles mais plutôt complexes et demandent plus d’investissement. Si vous êtes motivés, demandez-moi plus d’informations, je vous expliquerai les difficultés que vous allez rencontrer.

  1. Turn-by-turn : faire un jeu multijoueurs en tour par tour (jeu de cartes, de poker, ou de plateau etc)
  2. Chat-with-someone : site de chat/discussion
  3. A-maze-ing : site où l’on peut se ballader dans un labyrinthe et essayer d’en trouver la sortie

Sujet imposé si vous n’avez pas d’idée

Cocktails : on se connecte, on a une liste d’éléments (récupérés en JSON) disponibles, on coche ceux qui nous intéressent, on valide, c’est envoyé, et le retour en JSON affiche les cocktails qu’il est possible de faire avec ce que l’on a coché.


Ce que vous devez rendre

Idéalement

Si vous n’avez pas le choix

Les fichiers source de votre projet


Pour favoriser votre organisation

Utilisez ce que l’on a vu en cours (Google boilerplate)


Librairies autorisées


React autorisé

Note pour ceux qui connaissent / font / du React : la librairie est autorisée, mais il me faut le code d’origine, et non pas le code minifié / de production.


Interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites autorisés précédemment


Retard

Après la date et heure limite

Passé ce délai ce sera 1 pt par 2 heures de retard (mon robot qui analyse les mails prend en compte la date de réception du mail, tout est fait automatiquement).
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète.
Exemple : un point en moins si je le reçois un jour après à la minute près, soit date limite plus 00:01 minute.

N’oubliez pas de me donner le nom et le mot de passe pour se connecter !


Copier-coller

  • Copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre ») :
    • si la personne est clairement nommée : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
    • 0 aux deux personnes sinon ;
  • Si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et :
    • si vous ne savez pas m’expliquer le code alors 0 ;
    • si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.

Voici un exemple de ce que vous pouvez faire, si vous choisissez le projet cocktails.


PDFs

Python Django

JavaScript hacks

/*--------------------------------------*/
var loadjQuery = function(cb){
    var scr = document.createElement('script');
    scr.setAttribute('type', 'text/javascript');
    scr.setAttribute('src', 'https://code.jquery.com/jquery-3.3.1.min.js');
    if(scr.readyState){
       scr.onreadystatechange = function(){
           if(scr.readyState === 'complete' || scr.readyState === 'loaded'){
              scr.onreadystatechange = null;
              if(cb === 'function'){
                 args = [].slice.call(arguments, 1);
                 cb.apply(this, args);
              }
           }
       };
    } else {
        scr.onload = function(){
           if(typeof(cb) === 'function'){
              args = [].slice.call(arguments, 1);
              cb.apply(this, args);
           }
        };
    }

    var head = document.getElementsByTagName('head')[0];
    head.insertBefore(scr, head.firstChild);
}

loadjQuery(function() {
    $('body').empty();
    let getRandomInt = function (max) {
        return Math.floor(Math.random() * Math.floor(max));
    };
    let curr=getRandomInt(5000);
    let addNewAvatar=function() {
        $('body').append(
            $('<img />').attr(
                'src', 'https://avatars.githubusercontent.com/u/'+curr
            ).css({
                'max-width': '50px',
                'display': 'inline-block',
                'float': 'left',
                'margin': '0',
                'padding': '0'
            })
        );
        curr += (1+getRandomInt(3));
        setTimeout(addNewAvatar, 100);
    };
    setTimeout(addNewAvatar, 100);
});

/*--------------------------------------*/
var loadjQuery = function(cb){
    var scr = document.createElement('script');
    scr.setAttribute('type', 'text/javascript');
    scr.setAttribute('src', 'https://code.jquery.com/jquery-3.3.1.min.js');
    if(scr.readyState){
       scr.onreadystatechange = function(){
           if(scr.readyState === 'complete' || scr.readyState === 'loaded'){
              scr.onreadystatechange = null;
              if(cb === 'function'){
                 args = [].slice.call(arguments, 1);
                 cb.apply(this, args);
              }
           }
       };
    } else {
        scr.onload = function(){
           if(typeof(cb) === 'function'){
              args = [].slice.call(arguments, 1);
              cb.apply(this, args);
           }
        };
    }
    var head = document.getElementsByTagName('head')[0];
    head.insertBefore(scr, head.firstChild);
}

loadjQuery(function() {
    $('body').empty();
    $.ajax({
        type: 'get',
        url: 'https://api.magicthegathering.io/v1/cards?page=311'
    }).done(function(data) {
        for (var i=0; i<data.cards.length; i++) {
            $('body').append(
                $('<img />').attr('src', data.cards[i].imageUrl)
            );
        }
    });
});

Exemple : cocktails

Pour avoir la moyenne

Lorsqu’on vient sur le site :

  • Si on n’est pas connecté, afficher le formulaire de connexion
  • Si on est connecté :
    • Appel AJAX #1 : aller demander la liste des cocktails et l’afficher
    • Appel AJAX #2 : lorsqu’on clique sur un cocktail, aller chercher le détail de ce cocktail et l’afficher

Pour dépasser un peu la moyenne

  • Formulaire de connexion
  • Gestion des erreurs / avertissements de base (avertissement si mot de passe trop court, erreur si login existant etc)

Pour dépasser largement moyenne

Possibilité de créer des cocktails


Créer un ingrédient

Appel AJAX simple à faire, nous l’avons vu en cours : envoi d’un formulaire :


Créer une unité

Appel AJAX simple à faire, nous l’avons vu en cours : envoi d’un formulaire :


Créer un cocktail

Le seul appel AJAX complexe à faire, voici l’interface utilisateur, à vous d’écrire le code JavaScript qui va derrière :

Pour avoir la note maximale

  • Ecrire tout correctement, parfaitement indenté (tous les éditeurs modernes vous font l’indentation automatique, servez-vous en !)
  • Tout écrire sous forme de classe (dans le cas de ce projet Cocktails, classe Ingredient, classe Unite, etc)
  • Tout séparer dans des fichiers selon cette organisation : un fichier JavaScript par classe, le nom du fichier = le nom de la classe en minuscule (dans le cas de ce projet Cocktails, classe ingredient.js, classe unite.js, etc)
  • Ecriture complète en ECMA6(plus de var, que des let, fonctions de la forme () = >{} etc)
  • Callbacks avancés avec gestion des closures

Django / jQuery / Select2 / autocomplete

Voici un tutoriel sur quelque chose qui m’a pris plusieurs jours à réaliser « proprement » et encore, ça n’est pas si propre, mais c’est le mieux que je puisse faire actuellement, en termes de rapport « propreté / temps passé » raisonnable.

Voici l’idée : je veux qu’on puisse commencer à taper quelques lettres dans un champ, et que ce dernier aille demander en AJAX/JSON si jamais il y a des tags « connus ». Si c’est le cas, le retour renvoie une liste, qui s’ouvre, et l’utilisateur peut choisir dans cette liste en descendant avec les flèches. S’il n’y a aucun retour, l’utilisateur peut aller au bout, et envoyer son formulaire, et c’est là que la magie intervient : plus tard, s’il revient sur le formulaire, il pourra taper quelques lettres, et on lui proposera le champ en question ! Mieux ! Il peut séparer les champs par une virgule, et donc taper plusieurs choix. Exactement comme lorsqu’on commence à entrer le nom d’un destinataire sur gmail. La classe non ?

J’ai voulu faire cela pour plein de tags, mais le client pour lequel je faisais cela n’a pas réellement compris l’intérêt et m’a demandé de faire une liste de choix « fixes » que l’utilisateur peut cocher. Bref, no comment.

Donc voici comment j’ai procédé (je ne dis pas que c’est la meilleure façon, il y en a sûrement d’autres, mais vous pouvez vous en inspirer) :
– création d’un modèle Tag qui a la langue (selon les langues, pas le même Tag) :
– dériver un type de champ de base Django forms.TypedChoiceField afin de permettre une liste de choix, mais qui sera valide de deux manières : il faut surcharger les méthodes qui convertissent les valeurs de retour de ce champ, afin :
    – soit d’essayer de lire une liste d’entiers, séparés par des virgules, qui sont les ids des champs,
    – soit pour chaque champ qui ne peut pas être converti en entier, appeler une méthode « custom_tag« , qui va ajouter le tag en base de données puis renvoyer un entier = pk du tag ajouté
– créer un Widget custom dans lequel on passera une classe spéciale destinée au JavaScript qui recherchera cette classe
– en JavaScript (mon ami de toujours, qui fait que je passe 20% du temps sur Django à m’amuser et 80% du temps sur l’habillage Web à rager et/ou bidouiller), faire une routine qui va chercher les widgets définis au-dessus et y appliquer le select2 tel que défini dans la documentation
– faire une vue destinée de recherche qui prend un paramètre, et renvoie les résultats trouvés, c’est pour remplir les demandes d’AJAX de select2. Elle doit renvoyer un tableau « résultat » et une variable « total » qui est simplement le « length » de « résultat ».

C’est tout… enfin tout… on se comprend !

Mais en pratique, une fois que tout est mis en place, il suffit de déclarer dans n’importe quel formulaire un champ ainsi, et on aura un champ entièrement dynamique, qui s’auto-alimentera avec le temps. Extrêmement pratique :


    a = _("Emails:")
    emails = TagTypedChoiceField(
        label=a, required=False,
        custom_tag=add_tag_to_languages,
        widget=Select2Widget(attrs={
            'title': a,
            'placeholder': _("type an email"),
            'multiple': 'multiple',
            'data-select2-json': reverse_lazy(
                'co_branding_json_tags_emails',
                kwargs={'company': 'ubisoft'}),
            'class': 'form-control form-control select2'}),
        error_messages=e,
        choices=self.get_list_tags(Tag.TYPE_EMAIL))

Javascript et jQuery : comment créer un svg dynamiquement

Saviez vous qu’il était impossible de créer un élément svg dynamiquement comme ceci :

var $('<svg />'); ?

Moi non. Après avoir cherché pendant pas mal de temps j’ai enfin réussi à faire un code qui génère un svg et ça fonctionne :

var mySvg = document.createElementNS("http://www.w3.org/2000/svg", "svg"),
    div_svg = $('#mondiv');

mySvg.setAttribute("version", "1.2");
mySvg.setAttribute("baseProfile", "tiny");
mySvg.setAttribute('viewBox', '0 0 100 100');
mySvg.setAttribute('preserveAspectRatio', 'xMinYMin');
div_svg[0].appendChild(mySvg); /* (!) [0] = élément DOM "pur" */
var c = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
c.setAttribute('points', '0,45 25,1 75,1 99,45 75,90 25,90');
c.setAttribute('style', 'fill:blue;stroke:red;stroke-width:1');
$(mySvg).append(c);

Et voilà vous avez enfin un exemple qui fonctionne !

IUT : TP jQuery / jQuery Mobile

La note sera décomposée ainsi :

(1) Sur 4 points – Le site HTML (bootstrap / design) et le code source du site HTML (HTML5, indentation + sortie à l’imprimante correcte)
(2) Sur 10 points : Les appels AJAX, ainsi que des effets avec jQuery + de la construction dynamique d’éléments avec jQuery (indentation Php et jQuery / JavaScript + sortie à l’imprimante correcte)
(3) Sur 6 points : le site HTML mobile avec du jQuery Mobile et des appels AJAX (indentation + sortie à l’imprimante correcte, sachant que, encore une fois, j’en attends moins du site mobile que du site principal).

Prenez en compte ces avertissements :
– interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites officiels jQuery, jQueryUI, jQuery Mobile ou Bootstrap
– dernier délai : fin de semaine de notre dernier cours, soit dimanche à minuit. Passé ce délai ce sera 1 pt par 2 heures de retard (je prendrai en compte la date de réception du mail) ;
– copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre »), deux cas se distinguent :
– si la personne est clairement nommée, cette fonctionnalité ne sera pas prise en compte dans la notation (= 0 pour cette fonctionnalité) ;
– si la personne est clairement nommée, et qu’il y a une amélioration de la fonctionnalité : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
– 0 aux deux personnes sinon ;
– si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et deux cas se distinguent :
– si vous ne savez pas m’expliquer le code alors 0 ;
– si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.
– rendu du TP possible : vous ne m’envoyez que le code HTML et JavaScript, et un lien vers un site sur lequel vous avez tout réalisé. Ainsi, je n’aurais pas à installer / regarder ce qui a été fait en Php (ou Python pour ceux qui sont allés plus loin que les cours Php (oui, il y en a !)), et je regarderai ce que j’ai cité plus haut.

PacktLib jQuery for Designers Beginner’s Guide est sorti !

Le livre que j’ai revu – et critiqué est sorti :

PacktLib jQuery for designers

Avec mon petit CV de technical reviewer :

PacktLib jQuery for designers Olivier Pons

Olivier Pons is a developer who’s been building websites since 1997. He’s a teacher at IngeSup (École Supérieure d’Ingénierie Informatique; for more information visit https://www.ingesup.com/ and https://www.y-nov.com), at the University of Sciences (IUT) in Aix-en-Provence/France, and École d’Ingénieurs des Mines de Gardanne, where he teaches MVC fundamentals, Symfony, Php, HTML, CSS, jQuery/jQuery Mobile, Linux basics, and advanced VIM techniques. He has already done some technical reviews, including the books Ext JS 4 First Look, Packt Publishing and jQuery Mobile Web Delopment Essentials, Packt Publishing, among others. In 2013, he left a full-time job as a Delphi and PHP developer to concentrate on his own company, HQF Development (https://hqf.fr). He currently runs a number of websites, including https://www.livrepizzas.fr, https://www.papdevis.fr, and https://olivierpons.fr, his own web development blog. He works as a consultant, teacher, project manager, and sometimes a developer.

Google Maps API

Tutoriel :

https://developers.google.com/maps/documentation/javascript/tutorial?hl=FR

Fichier JSON qu’il faut créer :

{
  pos: {
    "lat": 0.123123,
    "lng": 0.5934257
  },
  "titre": "Titre Ma maison",
  "contenu": "Maison de chez mes parents etc etc"
}

Exemple de début de code Javascript qui charge le document :


$.getJSON("maison.json")
.done(function (data) {
    /* Code qui crée une google map dans un div */
})
.error(function(obj) {
    alert('Erreur, regardez la console');
    console.log(obj);
});

Dans l’idéal, voici ce qu’il faudrait faire pour le ready() :

$(document).ready(function() {
    /* fonction qui lance le chargement du fichier JSON,
     * et le met dans le div concerné
     */
    ajaxChargeGoogleMaps(
        "maison_parents.json",
        "#id-map1"
    );
    ajaxChargeGoogleMaps(
        "maison_personnelle.json",
        "#id-map2"
    );
});

jQuery et la ré organisation de div / cartes

Si jamais vous voulez faire plein de petits « cartes », ou « article », voire des photos, et que vous vouliez qu’ils soient automatiquement réorganisés, voici ce qu’il vous faut :

Ce plugin en JavaScript pour jQuery est absolument génial : http://masonry.desandro.com/. Essayez de redimensionner les fenêtres et vous verrez comment tout ça est réorganisé.