diff options
author | Denise sur Lya <sekhmet@lya> | 2020-06-18 14:40:06 +0200 |
---|---|---|
committer | Denise sur Lya <sekhmet@lya> | 2020-06-18 14:40:06 +0200 |
commit | be2bf5155489b103e616845ffedb1a58c3808c48 (patch) | |
tree | 8faeaeac748ff13201037571d507b9bdc8fbfaaa | |
parent | a46e126967995e8483b4da81a1f3b586266ee86d (diff) | |
download | oms-be2bf5155489b103e616845ffedb1a58c3808c48.tar.gz oms-be2bf5155489b103e616845ffedb1a58c3808c48.tar.zst oms-be2bf5155489b103e616845ffedb1a58c3808c48.zip |
Changement de format pour l'export, ajout des boutons qui vont avec + divers
-rw-r--r-- | app.py | 45 | ||||
-rw-r--r-- | data/FAQ_data.txt | 19 | ||||
-rw-r--r-- | data/changelog_data.txt | 14 | ||||
-rw-r--r-- | gestion_donnees.py | 177 | ||||
-rw-r--r-- | static/outilspage.js | 26 | ||||
-rw-r--r-- | static/requetes.js | 51 | ||||
-rw-r--r-- | static/style.css | 13 | ||||
-rw-r--r-- | templates/base.html | 2 | ||||
-rw-r--r-- | templates/changelog.html | 3 | ||||
-rw-r--r-- | templates/faq.html | 2 | ||||
-rw-r--r-- | templates/index.html | 110 |
11 files changed, 325 insertions, 137 deletions
@@ -27,8 +27,8 @@ def index(): | |||
27 | ## charger les donneés dans le formulaire | 27 | ## charger les donneés dans le formulaire |
28 | fichier = flask.request.files['fichier_donnees'] | 28 | fichier = flask.request.files['fichier_donnees'] |
29 | 29 | ||
30 | val_form = fichier_texte_vers_configdonnees(fichier,liste_err) | 30 | val_form = fichier_json_vers_configdonnees(fichier,liste_err) |
31 | 31 | #return str(val_form['nb_data']) | |
32 | return flask.render_template("index.html",err=liste_err[1],valform=val_form) | 32 | return flask.render_template("index.html",err=liste_err[1],valform=val_form) |
33 | 33 | ||
34 | @app.route('/apropos') | 34 | @app.route('/apropos') |
@@ -46,9 +46,10 @@ def courbe_image(ext): | |||
46 | config = gere_configuration(data,liste_err) | 46 | config = gere_configuration(data,liste_err) |
47 | l_jours,l_poids = gere_donneespoids(data,config["naissance"],liste_err) | 47 | l_jours,l_poids = gere_donneespoids(data,config["naissance"],liste_err) |
48 | 48 | ||
49 | # préparer l'export | 49 | texte = donnees_vers_json(l_jours,l_poids,config) |
50 | texte = configuration_vers_texte(config) | 50 | |
51 | texte += donnees_poids_vers_texte(l_jours,l_poids) | 51 | # noter le nom de l'enfant pour l'export |
52 | nomenfant = simplifie_nom(config['nom']) | ||
52 | 53 | ||
53 | # créer la figure | 54 | # créer la figure |
54 | try: | 55 | try: |
@@ -67,12 +68,14 @@ def courbe_image(ext): | |||
67 | reponse = flask.jsonify({ "result":result, | 68 | reponse = flask.jsonify({ "result":result, |
68 | "messages": liste_err[1], | 69 | "messages": liste_err[1], |
69 | "image": base64.b64encode(output.getvalue()).decode("ascii"), | 70 | "image": base64.b64encode(output.getvalue()).decode("ascii"), |
70 | "export_txt": texte}) | 71 | "export_txt": texte, |
72 | "nomenfant": nomenfant}) | ||
71 | else: | 73 | else: |
72 | reponse = flask.jsonify({ "result":result, | 74 | reponse = flask.jsonify({ "result":result, |
73 | "messages": liste_err[1]+liste_err[0], | 75 | "messages": liste_err[1]+liste_err[0], |
74 | "image": "", | 76 | "image": "", |
75 | "export_txt": texte}) | 77 | "export_txt": texte, |
78 | "nomenfant": nomenfant}) | ||
76 | return reponse | 79 | return reponse |
77 | #return flask.Response(base64.b64encode(output.getvalue()), mimetype='text/plain') | 80 | #return flask.Response(base64.b64encode(output.getvalue()), mimetype='text/plain') |
78 | elif ext == "png" and result == "success": | 81 | elif ext == "png" and result == "success": |
@@ -84,19 +87,21 @@ def courbe_image(ext): | |||
84 | 87 | ||
85 | #return flask.Response(base64.b64encode(output.getvalue()), mimetype='text/plain') | 88 | #return flask.Response(base64.b64encode(output.getvalue()), mimetype='text/plain') |
86 | 89 | ||
87 | @app.route("/export_donnees",methods=['POST']) | 90 | #@app.route("/export_donnees",methods=['POST']) |
88 | def export_donnees(): | 91 | #def export_donnees(): |
89 | # exporte les données au format texte | 92 | # # exporte les données au format texte |
90 | liste_err = initialise_erreurs() | 93 | # liste_err = initialise_erreurs() |
91 | data = flask.request.form | 94 | # data = flask.request.form |
92 | 95 | # | |
93 | config = gere_configuration(data,liste_err) | 96 | # config = gere_configuration(data,liste_err) |
94 | l_jours,l_poids = gere_donneespoids(data,config["naissance"],liste_err) | 97 | # l_jours,l_poids = gere_donneespoids(data,config["naissance"],liste_err) |
95 | 98 | # | |
96 | texte = configuration_vers_texte(config) | 99 | # texte = configuration_vers_texte(config) |
97 | texte += donnees_poids_vers_texte(l_jours,l_poids) | 100 | # texte += donnees_poids_vers_texte(l_jours,l_poids) |
98 | 101 | # | |
99 | return flask.Response(texte,mimetype="text/plain") | 102 | # #texte = donnees_vers_json(l_jours,l_poids,config) |
103 | # #return flask.Response(texte,mimetype="application/json") | ||
104 | # return flask.Response(texte,mimetype="text/plain") | ||
100 | 105 | ||
101 | @app.route("/faq") | 106 | @app.route("/faq") |
102 | def faq(): | 107 | def faq(): |
diff --git a/data/FAQ_data.txt b/data/FAQ_data.txt index fe2f5a5..2313fa8 100644 --- a/data/FAQ_data.txt +++ b/data/FAQ_data.txt | |||
@@ -1,10 +1,12 @@ | |||
1 | "Utilisation","Comment tracer la courbe ?","Remplissez le formulaire (vous pouvez laisser par défaut tous les champs qui ne vous « parlent » pas), puis cliquez sur ""Je veux la courbe !"". La courbe s'affiche plus bas. Si vous modifiez les données du formulaire, vous pouvez re-cliquer sur ce bouton pour la mettre à jour. Et c'est tout !" | 1 | "Utilisation","Comment tracer la courbe ?","Remplissez le formulaire (vous pouvez laisser par défaut tous les champs qui ne vous « parlent » pas), puis cliquez sur ""Je veux la courbe !"". La courbe s'affiche plus bas. Si vous modifiez les données du formulaire, vous pouvez re-cliquer sur ce bouton pour la mettre à jour. Et c'est tout ! Vous pouvez également télécharger la courbe en cliquant sur le bouton juste en dessous." |
2 | 2 | ||
3 | "Utilisation","Comment sauvegarder mes données pour une prochaine fois ?","L'outil ne propose pas de sauvegarde en ligne, car il ne garde aucune donnée personnelle. Quand vous demandez à tracer la courbe, il s'affiche en bas un champ de texte. Si vous copiez-collez ce contenu et le gardez dans un fichier, vous n'aurez pas à re-saisir les données. Utilisez la partie ""Importer le fichier de données"" puis ""Charger les données"" : les champs seront alors pré-remplis et vous pourrez les modifier ou ajouter des données (par exemple une pesée récente)." | 3 | "Utilisation","Comment sauvegarder mes données pour une prochaine fois ?","L'outil ne propose pas de sauvegarde en ligne, car il ne garde aucune donnée personnelle. Vous pouvez télécharger vos propres données (dans un format adapté) en cliquant sur « Télécharger les données ». Enregistrez ce fichier quelque part. Pour les réutiliser, utilisez la partie ""Importer le fichier de données"" puis ""Charger les données"" : les champs seront alors pré-remplis et vous pourrez les modifier ou ajouter des données (par exemple une pesée récente)." |
4 | 4 | ||
5 | "Utilisation","Je ne comprends pas comment saisir les données âge/poids !","Pour chaque pesée, vous avez le choix entre donner son âge, ou donner la date de la pesée. Pour la date de la pesée, il faut que vous ayiez rempli la date de naissance (sinon l'outil ne peut pas calculer l'âge !). Pour l'âge, vous pouvez indiquer en années, mois, semaines, jours, et mélanger plusieurs unités. Par exemple 2m3j pour « 2 mois 3 jours ». Ne remplissez qu'un des deux champs : âge ou date. Puis saisissez le poids en kilogrammes dans la colonne de droite. <br> | 5 | "Utilisation","Je ne comprends pas comment saisir les données âge/poids !","Pour chaque pesée, vous avez le choix entre donner son âge, ou donner la date de la pesée. Pour la date de la pesée, il faut que vous ayiez rempli la date de naissance (sinon l'outil ne peut pas calculer l'âge !). Pour l'âge, vous pouvez indiquer en années, mois, semaines, jours, et mélanger plusieurs unités. Par exemple 2m3j pour « 2 mois 3 jours ». Ne remplissez qu'un des deux champs : âge ou date. Puis saisissez le poids en kilogrammes dans la colonne de droite. <br> |
6 | Si vous manquez de lignes, vous pouvez cliquer sur ""Ajouter des lignes"" pour avoir plus de champs de données. Il n'y a pas de problème à laisser des champs vides, ils seront simplement ignorés." | 6 | Si vous manquez de lignes, vous pouvez cliquer sur ""Ajouter des lignes"" pour avoir plus de champs de données. Il n'y a pas de problème à laisser des champs vides, ils seront simplement ignorés." |
7 | 7 | ||
8 | "Utilisation","Une erreur s'affiche en bas de ma courbe, je ne comprends pas.","Si le message d'erreur n'est pas clair pour vous, c'est qu'il est probablement dû à un souci interne. Si vous le pouvez, contactez l'administratrice, en citant le message d'erreur et en donnant les données qui ont amené à cette erreur (fichier de données, ou données saisies). Merci d'avance ! :)" | ||
9 | |||
8 | "Courbe","À quoi sert ce site ?","Il sert à tracer la courbe de poids des bébés et jeunes enfants en fonction de leur âge, comme sur le carnet de santé, et la compare aux courbes de références de l'Organisation Mondiale de la Santé." | 10 | "Courbe","À quoi sert ce site ?","Il sert à tracer la courbe de poids des bébés et jeunes enfants en fonction de leur âge, comme sur le carnet de santé, et la compare aux courbes de références de l'Organisation Mondiale de la Santé." |
9 | 11 | ||
10 | "Courbe","Pourquoi des courbes OMS et pas des courbes françaises ?","Les particularités de ces données sont les suivantes : bébés et enfants choisis dans différents pays du monde (et non dans un seul pays), dans des familles raisonnablement aisées (pour éviter les problèmes liés à la malnutrition), et des bébés allaités. Plus d'infos <a href=""https://www.who.int/childgrowth/standards/technical_report/en/"">ici</a> (en anglais). L'idée générale était de donner une « référence » de croissance de l'enfant de l'espèce humaine. Cela ne veut pas dire que les courbes du carnet de santé français sont mauvaises (si vous avez celles datant d'avant 2018, elles sont un peu anciennes par contre), de fait, elles sont très peu différentes. Pour les autres pays je ne sais pas, je n'ai pas comparé." | 12 | "Courbe","Pourquoi des courbes OMS et pas des courbes françaises ?","Les particularités de ces données sont les suivantes : bébés et enfants choisis dans différents pays du monde (et non dans un seul pays), dans des familles raisonnablement aisées (pour éviter les problèmes liés à la malnutrition), et des bébés allaités. Plus d'infos <a href=""https://www.who.int/childgrowth/standards/technical_report/en/"">ici</a> (en anglais). L'idée générale était de donner une « référence » de croissance de l'enfant de l'espèce humaine. Cela ne veut pas dire que les courbes du carnet de santé français sont mauvaises (si vous avez celles datant d'avant 2018, elles sont un peu anciennes par contre), de fait, elles sont très peu différentes. Pour les autres pays je ne sais pas, je n'ai pas comparé." |
@@ -16,10 +18,21 @@ Si vous manquez de lignes, vous pouvez cliquer sur ""Ajouter des lignes"" pour a | |||
16 | "Courbe","Pourquoi faire des courbes de référence différenciées selon le sexe ?","Il se trouve que l'évolution de poids diffère selon ce critère. S'il s'agissait d'une simple différence de poids en moyenne, une courbe mixte serait adaptée (puisqu'on s'intéresse à l'allure de la courbe et non au poids absolu), mais les courbes sont légèrement différentes.<br> | 18 | "Courbe","Pourquoi faire des courbes de référence différenciées selon le sexe ?","Il se trouve que l'évolution de poids diffère selon ce critère. S'il s'agissait d'une simple différence de poids en moyenne, une courbe mixte serait adaptée (puisqu'on s'intéresse à l'allure de la courbe et non au poids absolu), mais les courbes sont légèrement différentes.<br> |
17 | Vous trouverez <a href=""static/courbe_oms_gf_1an.png"">ici</a> et <a href=""static/courbe_oms_gf_5ans.png"">là</a> deux graphiques où on voit les courbes de poids garçons et filles superposées." | 19 | Vous trouverez <a href=""static/courbe_oms_gf_1an.png"">ici</a> et <a href=""static/courbe_oms_gf_5ans.png"">là</a> deux graphiques où on voit les courbes de poids garçons et filles superposées." |
18 | 20 | ||
19 | "Courbe","Pourquoi une courbe de « neutre » ? Et c'est quoi ?","Pourquoi pas ? C'est simplement une courbe moyennée des courbes garçon/fille. Ce n'est absolument pas une référence réelle, mais ça ne coûtait rien d'essayer. Je n'ai aucune connaissance dans les données de croissance des enfants intersexes, et s'il existe pour ces enfants des courbes de référence, peut-être que celle-ci aurait du sens, peut-être pas. Elle permet accessoirement de générer une courbe « acceptable » même si on n'a pas spécifié sexe masculin/féminin. Au pire vous pouvez considérer que c'est une « courbe jouet »." | 21 | "Courbe","Pourquoi une courbe de « neutre » ? Et c'est quoi ?","Pourquoi pas ? C'est simplement une courbe moyennée des courbes garçon/fille. Ce n'est absolument pas une vraie référence, mais ça ne coûtait rien d'essayer. Je n'ai aucune connaissance dans les données de croissance des enfants intersexes, et s'il existe pour ces enfants des courbes de référence, peut-être que celle-ci aurait du sens, peut-être pas. Elle permet accessoirement de générer une courbe « acceptable » même si on n'a pas spécifié sexe masculin/féminin. Au pire vous pouvez considérer que c'est une « courbe jouet »." |
22 | |||
23 | "Courbe","C'est quoi la différence entre la courbe percentiles et moyenne/écarts-types ?","Ce sont deux manières de comparer son enfant à la « référence ». Si vous ne savez pas la différence entre une moyenne et une médiane, retenez juste que ce sont des calculs un peu différents, mais cela ne change pas l'allure de la courbe, si votre enfant « suit » un couloir sur un type de courbe ce sera pareil sur l'autre. Vous pouvez au pire choisir celle que vous préférez. ;) | ||
24 | <br>Pour les curieuses et les curieux : | ||
25 | <ul> | ||
26 | <li>Médiane et percentiles : si votre enfant est (par exemple) au 30e percentile, cela signifie que 29% des enfants sont plus petits que lui, et 31% sont plus grands. Cela donne une idée de où se situe l'enfant par rapport aux autres. <a href=""https://fr.wikipedia.org/wiki/Centile"">Plus d'infos (maths)</a></li> | ||
27 | <li>Moyenne et écart-types : la moyenne est obtenue en faisant la somme et en divisant par le nombre d'enfants. L'écart-type (noté σ ou z) est une sorte d'« écart moyen » à la moyenne. On regarde donc généralement la moyenne, la moyenne + 1σ, moyenne +2σ, moyenne -1 σ, etc. <a href=""https://fr.wikipedia.org/wiki/%C3%89cart_type"">Plus d'infos (maths)</a></li> | ||
28 | </ul> | ||
29 | Si la répartition des données est « bonne » (on parle de gaussienne entre matheuses et matheux), alors la moyenne correspond à la médiane, la moyenne + 1σ correspond environ au 84e percentile, la moyenne -1σ correspond au 16e percentile. Pour ces données, il semble que ce soit assez proche d'une gaussienne." | ||
20 | 30 | ||
21 | "Divers","Pourquoi cet outil ?","Tout a commencé sur le <a href=""https://forum.lllfrance.org/"">forum de La Leche League</a>, où de nombreuses mamans (et parfois quelques papas) viennent poser des questions sur l'allaitement. Souvent, se pose la question de la prise de poids du bébé, qui est un bon indicateur de si le bébé reçoit assez de lait. Le poids dans l'absolu étant peu pertinent, il est utile de « tracer » la courbe de poids. Il n'existe actuellement que peu d'outils qui permettent de le faire (l'OMS en fournit un qui ne fonctionne que sous windows), en voici un." | 31 | "Divers","Pourquoi cet outil ?","Tout a commencé sur le <a href=""https://forum.lllfrance.org/"">forum de La Leche League</a>, où de nombreuses mamans (et parfois quelques papas) viennent poser des questions sur l'allaitement. Souvent, se pose la question de la prise de poids du bébé, qui est un bon indicateur de si le bébé reçoit assez de lait. Le poids dans l'absolu étant peu pertinent, il est utile de « tracer » la courbe de poids. Il n'existe actuellement que peu d'outils qui permettent de le faire (l'OMS en fournit un qui ne fonctionne que sous windows), en voici un." |
22 | 32 | ||
23 | "Divers","Mais qui es tu donc ?","Je suis une de ces nombreuses mamans qui s'est posée un jour (et un autre jour aussi) la question de la prise de poids de son enfant. Adepte de solutions libres et multi-plateforme, je n'ai rien trouvée qui me permette de tracer cette courbe, que ce soit pour mon enfant ou celui des autres. Je suis par ailleurs férue de programmation (et je l'enseigne d'ailleurs), et donc... voilà." | 33 | "Divers","Mais qui es tu donc ?","Je suis une de ces nombreuses mamans qui s'est posée un jour (et un autre jour aussi) la question de la prise de poids de son enfant. Adepte de solutions libres et multi-plateforme, je n'ai rien trouvée qui me permette de tracer cette courbe, que ce soit pour mon enfant ou celui des autres. Je suis par ailleurs férue de programmation (et je l'enseigne d'ailleurs), et donc... voilà." |
24 | 34 | ||
25 | "Technique","Quelle est la technologie utilisée derrière ?","Il s'agit de <a href=""https://flask.palletsprojects.com/en/1.1.x/"">flask</a>, un petit framework de développement web en <a href=""https://www.python.org/"">python</a>. Il y a une petite dose de <a href=""https://developer.mozilla.org/fr/docs/Web/JavaScript"">JavaScript</a> pour assaisonner le tout, et voilà." | 35 | "Technique","Quelle est la technologie utilisée derrière ?","Il s'agit de <a href=""https://flask.palletsprojects.com/en/1.1.x/"">flask</a>, un petit framework de développement web en <a href=""https://www.python.org/"">python</a>. Il y a une petite dose de <a href=""https://developer.mozilla.org/fr/docs/Web/JavaScript"">JavaScript</a> pour assaisonner le tout, et voilà." |
36 | |||
37 | "Technique","J'ai trouvé un affreux bug !","N'hésitez pas à me contacter avec le plus de détails possibles à ce sujet. Par exemple quelles données, quelles manipulations vous ont amené.e à ce bug. Vous pouvez aussi préciser votre navigateur. Plus vous me fournissez d'informations, plus j'ai de chances de résoudre le bug !" | ||
38 | |||
diff --git a/data/changelog_data.txt b/data/changelog_data.txt index e5b81a0..f939444 100644 --- a/data/changelog_data.txt +++ b/data/changelog_data.txt | |||
@@ -1,3 +1,15 @@ | |||
1 | "Version 0.4","18/06/2020","<ul> | ||
2 | <li>Mis certaines sections en masquées par défaut, on peut cliquer pour les afficher</li> | ||
3 | <li>Encore des ajouts dans la FAQ</li> | ||
4 | <li>Si je continue comme ça je vais arriver à une version 1.0 avant d'avoir fini !</li> | ||
5 | </ul>" | ||
6 | |||
7 | "Version 0.3","17/06/2020","<ul> | ||
8 | <li>Le format d'export est maintenant du json (vos anciennes sauvegardes ne marchent plus, désolée !)</li> | ||
9 | <li>Bouton de téléchargement des données et de la courbe, avec un nom sympa en plus (« courbe_nomenfant.png » par exemple)</li> | ||
10 | <li>Le texte ""explicite"" d'export est maintenant caché par défaut (on peut quand même l'avoir en cliquant dessus)</li> | ||
11 | </ul>" | ||
12 | |||
1 | "Version 0.2","16/06/2020","<ul> | 13 | "Version 0.2","16/06/2020","<ul> |
2 | <li>Mise en place du changelog (sans blague)</li> | 14 | <li>Mise en place du changelog (sans blague)</li> |
3 | <li>Courbe ""sexe neutre"" expérimentale</li> | 15 | <li>Courbe ""sexe neutre"" expérimentale</li> |
@@ -6,7 +18,7 @@ | |||
6 | <li>Mise à jour de la FAQ</li> | 18 | <li>Mise à jour de la FAQ</li> |
7 | </ul>" | 19 | </ul>" |
8 | 20 | ||
9 | "Version 0.1","14/06/2020","Mise en place du site web, en cours de développement. | 21 | "Version 0.1","14/06/2020","<p>Mise en place du site web, en cours de développement.</p> |
10 | <ul> | 22 | <ul> |
11 | <li>Tracé de la courbe</li> | 23 | <li>Tracé de la courbe</li> |
12 | <li>Export/import des données</li> | 24 | <li>Export/import des données</li> |
diff --git a/gestion_donnees.py b/gestion_donnees.py index 71c9623..a2d0a1e 100644 --- a/gestion_donnees.py +++ b/gestion_donnees.py | |||
@@ -4,13 +4,15 @@ | |||
4 | from configuration import * | 4 | from configuration import * |
5 | from gestion_erreurs import * | 5 | from gestion_erreurs import * |
6 | import datetime | 6 | import datetime |
7 | import json | ||
8 | import unidecode | ||
7 | 9 | ||
8 | 10 | ||
9 | ############ Fonctions de conversion | 11 | ############ Fonctions de conversion |
10 | 12 | ||
11 | def convertit_jours_vers_python(chaine,liste_err): | 13 | def convertit_jours_vers_python(chaine,liste_err): |
12 | """ convertit une chaine de type 1a 3m 1s 10j en jours | 14 | """ convertit une chaine de type 1a 3m 1s 10j en jours |
13 | Renvoie un nombre de jours en entiers. | 15 | Renvoie un nombre de jours en float |
14 | Si un des caractères n'est ni un nombre, ni une lettre "autorisée" ni une espace, | 16 | Si un des caractères n'est ni un nombre, ni une lettre "autorisée" ni une espace, |
15 | on affiche un warning et on ignore ce caractère | 17 | on affiche un warning et on ignore ce caractère |
16 | """ | 18 | """ |
@@ -41,19 +43,19 @@ def convertit_jours_vers_python(chaine,liste_err): | |||
41 | warning("convertit_jour_vers_python : caractère invalide : "+lettre,liste_err) | 43 | warning("convertit_jour_vers_python : caractère invalide : "+lettre,liste_err) |
42 | # à la fin s'il reste qqch on le garde dans les jours | 44 | # à la fin s'il reste qqch on le garde dans les jours |
43 | if chainenombre != "": | 45 | if chainenombre != "": |
44 | agejour += int(chainenombre) | 46 | agejours += int(chainenombre) |
45 | if agejours<0: | 47 | if agejours<0: |
46 | warning("L'âge est négatif !",liste_err) | 48 | warning("L'âge est négatif !",liste_err) |
47 | agejours = 0 | 49 | agejours = 0 |
48 | return round(agejours) | 50 | return agejours |
49 | 51 | ||
50 | def convertit_age_vers_texte(nombre): | 52 | def convertit_age_vers_texte(nombre): |
51 | """ convertit un nombre de jours en un truc plus lisible en mois, années, jours | 53 | """ convertit un nombre de jours en un truc plus lisible en mois, années, jours |
52 | et renvoie une chaîne sous la forme 3a2m1j par exemple""" | 54 | et renvoie une chaîne sous la forme 3a2m1j par exemple""" |
53 | annees = int(nombre / jours_dans_annee) | 55 | annees = int(nombre / jours_dans_annee) |
54 | restant = nombre - round(annees*jours_dans_annee) | 56 | restant = nombre - annees*jours_dans_annee |
55 | mois = int(restant/jours_dans_mois) | 57 | mois = int(restant/jours_dans_mois) |
56 | jours= nombre - round(mois*jours_dans_mois + annees*jours_dans_annee) | 58 | jours= round(nombre - mois*jours_dans_mois - annees*jours_dans_annee) |
57 | 59 | ||
58 | chaine = "" | 60 | chaine = "" |
59 | if annees >0: | 61 | if annees >0: |
@@ -64,6 +66,18 @@ def convertit_age_vers_texte(nombre): | |||
64 | chaine += str(jours)+"j" | 66 | chaine += str(jours)+"j" |
65 | return chaine | 67 | return chaine |
66 | ########################## | 68 | ########################## |
69 | |||
70 | |||
71 | def simplifie_nom(chaine): | ||
72 | """ simplifie le nom chaine afin d'en faire une extension | ||
73 | pour le nom du fichier. Met tout en minuscules et vire les caractères spéciaux | ||
74 | et max 15 caractères""" | ||
75 | chaine2 = "" | ||
76 | for l in chaine: | ||
77 | if l.isalpha(): | ||
78 | chaine2+=l | ||
79 | chaine2 = unidecode.unidecode(chaine2) | ||
80 | return chaine2[:15] | ||
67 | 81 | ||
68 | def convertit_poids_vers_python(chaine,liste_err): | 82 | def convertit_poids_vers_python(chaine,liste_err): |
69 | """ convertit une chaine vers un float qui est le poids. | 83 | """ convertit une chaine vers un float qui est le poids. |
@@ -82,9 +96,9 @@ def convertit_poids_vers_python(chaine,liste_err): | |||
82 | poids = 0 | 96 | poids = 0 |
83 | return poids | 97 | return poids |
84 | 98 | ||
85 | def convertit_poids_vers_texte(poids): | 99 | #def convertit_poids_vers_texte(poids): |
86 | """ convertit un poids vers du texte. Rien à dire là pour l'instant """ | 100 | # """ convertit un poids vers du texte. Rien à dire là pour l'instant """ |
87 | return str(poids) | 101 | # return str(poids) |
88 | 102 | ||
89 | ######################### | 103 | ######################### |
90 | 104 | ||
@@ -101,7 +115,7 @@ def convertit_date_vers_python(chaine,liste_err): | |||
101 | date = datetime.date(int(liste[0]),int(liste[1]),int(liste[2])) | 115 | date = datetime.date(int(liste[0]),int(liste[1]),int(liste[2])) |
102 | except: | 116 | except: |
103 | date = "" | 117 | date = "" |
104 | warning("Impossible de lire la date "+chaine) | 118 | warning("Impossible de lire la date "+chaine,liste_err) |
105 | return date | 119 | return date |
106 | 120 | ||
107 | def convertit_date_vers_texte(date): | 121 | def convertit_date_vers_texte(date): |
@@ -127,7 +141,7 @@ def delta_date(date1,datenaissance): | |||
127 | 141 | ||
128 | 142 | ||
129 | def gere_configuration(data,liste_err): | 143 | def gere_configuration(data,liste_err): |
130 | """ prend en argument le dictionnaire de requête (configuratio imparfaite), et | 144 | """ prend en argument le dictionnaire de requête (configuration imparfaite), et |
131 | construit le dictionnaire de configuration qui va bien. | 145 | construit le dictionnaire de configuration qui va bien. |
132 | Vérifie que chaque entrée est cohérente évidemment.""" | 146 | Vérifie que chaque entrée est cohérente évidemment.""" |
133 | configuration = {} | 147 | configuration = {} |
@@ -176,7 +190,7 @@ def gere_configuration(data,liste_err): | |||
176 | configuration["maxi"] = convertit_jours_vers_python(maxi,liste_err) | 190 | configuration["maxi"] = convertit_jours_vers_python(maxi,liste_err) |
177 | 191 | ||
178 | # dimensions du graphique | 192 | # dimensions du graphique |
179 | largeur = data.get("largeur") | 193 | largeur = data.get("largeur","") |
180 | if largeur == "": | 194 | if largeur == "": |
181 | largeur = largeur_graphique | 195 | largeur = largeur_graphique |
182 | else: | 196 | else: |
@@ -193,7 +207,7 @@ def gere_configuration(data,liste_err): | |||
193 | warning("Largeur trop petite !",liste_err) | 207 | warning("Largeur trop petite !",liste_err) |
194 | configuration["largeur"] = largeur | 208 | configuration["largeur"] = largeur |
195 | 209 | ||
196 | hauteur = data.get("hauteur") | 210 | hauteur = data.get("hauteur","") |
197 | if hauteur == "": | 211 | if hauteur == "": |
198 | hauteur = hauteur_graphique | 212 | hauteur = hauteur_graphique |
199 | else: | 213 | else: |
@@ -225,21 +239,19 @@ def gere_configuration(data,liste_err): | |||
225 | positionlegende = "upper left" | 239 | positionlegende = "upper left" |
226 | configuration["positionlegende"] = positionlegende | 240 | configuration["positionlegende"] = positionlegende |
227 | 241 | ||
228 | |||
229 | |||
230 | return configuration | 242 | return configuration |
231 | 243 | ||
232 | def configuration_vers_texte(config): | 244 | #def configuration_vers_texte(config): |
233 | """ exporte le texte associé à une configuration | 245 | # """ exporte le texte associé à une configuration |
234 | on dumpe simplement sauf pour maxi """ | 246 | # on dumpe simplement sauf pour maxi """ |
235 | texte = "# Section configuration\n" | 247 | # texte = "# Section configuration\n" |
236 | for (cle,val) in config.items(): | 248 | # for (cle,val) in config.items(): |
237 | if cle != "maxi": | 249 | # if cle != "maxi": |
238 | texte+= cle + "=" + str(val) + "\n" | 250 | # texte+= cle + "=" + str(val) + "\n" |
239 | else: | 251 | # else: |
240 | texte+= cle + "=" + convertit_age_vers_texte(val)+"\n" | 252 | # texte+= cle + "=" + convertit_age_vers_texte(val)+"\n" |
241 | texte +="\n" | 253 | # texte +="\n" |
242 | return texte | 254 | # return texte |
243 | 255 | ||
244 | 256 | ||
245 | def gere_donneespoids(data,naissance,liste_err): | 257 | def gere_donneespoids(data,naissance,liste_err): |
@@ -279,46 +291,87 @@ def gere_donneespoids(data,naissance,liste_err): | |||
279 | return (l_jours,l_poids) | 291 | return (l_jours,l_poids) |
280 | 292 | ||
281 | 293 | ||
282 | def donnees_poids_vers_texte(l_jours,l_poids): | 294 | #def donnees_poids_vers_texte(l_jours,l_poids): |
283 | """ retourne le texte correspondant aux données de poids """ | 295 | # """ retourne le texte correspondant aux données de poids """ |
284 | texte = "# Section données\n" | 296 | # texte = "# Section données\n" |
285 | 297 | # | |
286 | for i in range(len(l_poids)): | 298 | # for i in range(len(l_poids)): |
287 | texte +=convertit_age_vers_texte(l_jours[i])+","+convertit_poids_vers_texte(l_poids[i])+"\n" | 299 | # texte +=convertit_age_vers_texte(l_jours[i])+","+convertit_poids_vers_texte(l_poids[i])+"\n" |
300 | # | ||
301 | # texte+="\n" | ||
302 | # return texte | ||
303 | |||
304 | |||
305 | |||
306 | |||
307 | |||
308 | def donnees_vers_json(l_jours,l_poids,config): | ||
309 | """ retourne le json à renvoyer""" | ||
310 | gros_dico = config.copy() | ||
311 | l_jours2 = [convertit_age_vers_texte(d) for d in l_jours] | ||
312 | gros_dico["data_j"] = l_jours2 | ||
313 | gros_dico["data_p"] = l_poids | ||
314 | # gérer la date de naissance | ||
315 | if gros_dico.get("naissance","") != "": | ||
316 | gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"]) | ||
317 | # gérer l'age maxi | ||
318 | gros_dico["maxi"] = convertit_age_vers_texte(gros_dico["maxi"]) | ||
288 | 319 | ||
289 | texte+="\n" | 320 | return json.dumps(gros_dico, indent=2,ensure_ascii=False ) |
290 | return texte | ||
291 | 321 | ||
322 | #def fichier_texte_vers_configdonnees(fichier,liste_err): | ||
323 | # """ prend le texte importé et l'exporte vers configuration et données | ||
324 | # sous forme de valeurs du formulaire """ | ||
325 | # | ||
326 | # valform = {} | ||
327 | # indice_formulaire = 0 # l'indice du formulaire pour les données : age_1, date_1, poids_1 etc | ||
328 | # num_ligne = 0 | ||
329 | # lignes = fichier.readlines() | ||
330 | # for ligne in lignes: | ||
331 | # num_ligne +=1 | ||
332 | # ligne = str(ligne,"utf8") | ||
333 | # ligne = ligne.rstrip("\n") | ||
334 | # if ligne != "" and ligne[0] != "#" and not(ligne.isspace()): # les lignes commençant par # sont des commentaires | ||
335 | # # On essaie de partitionner pour voir | ||
336 | # (var,egal,val) = ligne.partition("=") | ||
337 | # if egal == "=": # c'est une ligne de config | ||
338 | # valform[var] = val | ||
339 | # else: | ||
340 | # (age,virgule,poids) = ligne.partition(",") # On partitionne avec , | ||
341 | # if virgule == ",": | ||
342 | # # c'est une ligne de data | ||
343 | # valform["age_"+str(indice_formulaire)] = age | ||
344 | # valform["poids_"+str(indice_formulaire)] = poids | ||
345 | # indice_formulaire +=1 | ||
346 | # | ||
347 | # else: | ||
348 | # warning("La ligne "+str(num_ligne)+" n'est pas reconnue et sera ignorée : <"+ligne+">",liste_err) | ||
349 | # | ||
350 | # #le nb max du formulaire | ||
351 | # valform["nb_data"] = max(indice_formulaire +2,nombre_lignes_form) | ||
352 | # | ||
353 | # return valform | ||
292 | 354 | ||
293 | def fichier_texte_vers_configdonnees(fichier,liste_err): | 355 | def fichier_json_vers_configdonnees(fichier,liste_err): |
294 | """ prend le texte importé et l'exporte vers configuration et données | 356 | """ prend le json importé et l'exporte vers les valeurs du formulaire """ |
295 | sous forme de valeurs du formulaire """ | 357 | chaine = fichier.read() |
358 | valform = json.loads(chaine) | ||
359 | # Il faut maintenant récupérer les l_jours et l_poids puis les remettre | ||
360 | # sous forme de age_i et poids_i | ||
361 | l_jours= valform.get("data_j",[]) | ||
362 | l_poids=valform.get("data_p",[]) | ||
363 | if len(l_poids) != len(l_jours): | ||
364 | warning("Lecture du json : les données sont incohérentes (listes de taille différentes et/ou pb de lecture") | ||
365 | long = min(len(l_jours),len(l_poids)) | ||
366 | else: | ||
367 | long = len(l_jours) | ||
368 | for i in range(long): | ||
369 | valform["age_"+str(i)] = l_jours[i] | ||
370 | valform["poids_"+str(i)] = l_poids[i] | ||
371 | |||
372 | valform["nb_data"] = max(long +2,nombre_lignes_form) | ||
296 | 373 | ||
297 | valform = {} | 374 | return valform |
298 | indice_formulaire = 0 # l'indice du formulaire pour les données : age_1, date_1, poids_1 etc | ||
299 | num_ligne = 0 | ||
300 | lignes = fichier.readlines() | ||
301 | for ligne in lignes: | ||
302 | num_ligne +=1 | ||
303 | ligne = str(ligne,"utf8") | ||
304 | ligne = ligne.rstrip("\n") | ||
305 | if ligne != "" and ligne[0] != "#" and not(ligne.isspace()): # les lignes commençant par # sont des commentaires | ||
306 | # On essaie de partitionner pour voir | ||
307 | (var,egal,val) = ligne.partition("=") | ||
308 | if egal == "=": # c'est une ligne de config | ||
309 | valform[var] = val | ||
310 | else: | ||
311 | (age,virgule,poids) = ligne.partition(",") # On partitionne avec , | ||
312 | if virgule == ",": | ||
313 | # c'est une ligne de data | ||
314 | valform["age_"+str(indice_formulaire)] = age | ||
315 | valform["poids_"+str(indice_formulaire)] = poids | ||
316 | indice_formulaire +=1 | ||
317 | |||
318 | else: | ||
319 | warning("La ligne "+str(num_ligne)+" n'est pas reconnue et sera ignorée : <"+ligne+">",liste_err) | ||
320 | 375 | ||
321 | #le nb max du formulaire | ||
322 | valform["nb_data"] = indice_formulaire +2 | ||
323 | 376 | ||
324 | return valform | 377 | \ No newline at end of file |
diff --git a/static/outilspage.js b/static/outilspage.js index de87963..8da9e88 100644 --- a/static/outilspage.js +++ b/static/outilspage.js | |||
@@ -23,3 +23,29 @@ function ajoutelignes() | |||
23 | } | 23 | } |
24 | 24 | ||
25 | } | 25 | } |
26 | |||
27 | // Affichage de la textarea "export" | ||
28 | function affiche_export() | ||
29 | { | ||
30 | document.getElementById("export").style.display = "block" ; | ||
31 | |||
32 | } | ||
33 | |||
34 | function affiche_cache(id,elemcourant) | ||
35 | { | ||
36 | // affiche et/ou cache l'élément id, tout en changeant le this | ||
37 | // en afficher/masquer | ||
38 | elem = document.getElementById(id) | ||
39 | if(elem.style.display == "block") | ||
40 | { | ||
41 | elem.style.display = "none"; | ||
42 | elemcourant.innerHTML = "Afficher" ; | ||
43 | } | ||
44 | else | ||
45 | { | ||
46 | elem.style.display = "block" ; | ||
47 | elemcourant.innerHTML = "Masquer" ; | ||
48 | |||
49 | } | ||
50 | |||
51 | } | ||
diff --git a/static/requetes.js b/static/requetes.js index 072e880..b7e719a 100644 --- a/static/requetes.js +++ b/static/requetes.js | |||
@@ -9,21 +9,34 @@ function appelle_image() | |||
9 | requete.onreadystatechange = function() | 9 | requete.onreadystatechange = function() |
10 | { | 10 | { |
11 | if (this.readyState == 4 && this.status == 200) { | 11 | if (this.readyState == 4 && this.status == 200) { |
12 | // On nettoie | ||
13 | nettoie_erreurs() | ||
14 | |||
12 | // on récupère les différents champs de la réponse | 15 | // on récupère les différents champs de la réponse |
13 | var result = this.response.result ; | 16 | var result = this.response.result ; |
14 | var image = this.response.image ; | 17 | var image = this.response.image ; |
15 | var liste_warnings = this.response.messages | 18 | var liste_warnings = this.response.messages |
16 | var texte = this.response.export_txt; | 19 | var texte = this.response.export_txt; |
20 | var nomenfant = this.response.nomenfant ; | ||
21 | |||
17 | // on affiche l'export des données | 22 | // on affiche l'export des données |
18 | document.getElementById('export').innerHTML = texte; | 23 | document.getElementById('export').innerHTML = texte; |
19 | document.getElementById('sectionexport').style.display = "block"; | 24 | document.getElementById('sectionexport').style.display = "block"; |
25 | |||
26 | |||
27 | var boutondl = document.getElementById("export_dl") ; | ||
28 | boutondl.setAttribute('onclick',"download_file('donnees_"+nomenfant+".json', 'application/json;charset=utf-8','"+encodeURIComponent(texte) +"')") | ||
29 | |||
20 | 30 | ||
21 | if(result == "success") | 31 | if(result == "success") |
22 | { | 32 | { |
23 | // On affiche l'image | 33 | // On affiche l'image |
24 | document.getElementById('courbe').src = 'data:image/png;base64,'+(image); | 34 | document.getElementById('courbe').src = 'data:image/png;base64,'+(image); |
25 | document.getElementById('sectioncourbe').style.display = "block"; | 35 | document.getElementById('sectioncourbe').style.display = "block"; |
26 | 36 | ||
37 | //document.getElementById("courbe_dl").setAttribute('href', 'data:image/png;base64,' + image); | ||
38 | boutondl = document.getElementById("courbe_dl") ; | ||
39 | boutondl.setAttribute('onclick',"download_file('courbe_"+nomenfant+".png', 'image/png;base64','"+image +"')") | ||
27 | 40 | ||
28 | // Si y'a eu des warnings, faut les afficher | 41 | // Si y'a eu des warnings, faut les afficher |
29 | if(liste_warnings.length != 0) | 42 | if(liste_warnings.length != 0) |
@@ -41,7 +54,7 @@ function appelle_image() | |||
41 | } | 54 | } |
42 | else{ // si la génération de l'image a merdé | 55 | else{ // si la génération de l'image a merdé |
43 | 56 | ||
44 | // afficher la liste des warnings | 57 | // afficher la liste des erreurs |
45 | var elem_div = document.getElementById('courbe_erreurs') ; | 58 | var elem_div = document.getElementById('courbe_erreurs') ; |
46 | elem_div.style.display = "block" ; | 59 | elem_div.style.display = "block" ; |
47 | var ul = elem_div.children[1] ; | 60 | var ul = elem_div.children[1] ; |
@@ -58,3 +71,35 @@ function appelle_image() | |||
58 | requete.open("POST","courbe/b64",true) | 71 | requete.open("POST","courbe/b64",true) |
59 | requete.send(formData) | 72 | requete.send(formData) |
60 | } | 73 | } |
74 | |||
75 | function nettoie_erreurs() | ||
76 | { | ||
77 | // fonction qui nettoie les erreurs affichées sur la page | ||
78 | // vider les warnings | ||
79 | var elem_div = document.getElementById('courbe_warnings') ; | ||
80 | elem_div.style.display = "none" ; | ||
81 | var ul = elem_div.children[1] ; | ||
82 | ul.innerHTML = ""; | ||
83 | |||
84 | // vider les erreurs | ||
85 | elem_div = document.getElementById('courbe_erreurs') ; | ||
86 | elem_div.style.display = "none" ; | ||
87 | ul = elem_div.children[1] ; | ||
88 | ul.innerHTML = "" ; | ||
89 | |||
90 | } | ||
91 | |||
92 | |||
93 | function download_file(filename,mimetype,data) { | ||
94 | var element = document.createElement('a'); | ||
95 | element.setAttribute('href', 'data:'+mimetype+',' + data); | ||
96 | element.setAttribute('download', filename); | ||
97 | |||
98 | element.style.display = 'none'; | ||
99 | document.body.appendChild(element); | ||
100 | |||
101 | element.click(); | ||
102 | |||
103 | document.body.removeChild(element); | ||
104 | |||
105 | } | ||
diff --git a/static/style.css b/static/style.css index 3113832..58fdd24 100644 --- a/static/style.css +++ b/static/style.css | |||
@@ -13,6 +13,7 @@ body { | |||
13 | #export { | 13 | #export { |
14 | width: 25em; | 14 | width: 25em; |
15 | height: 20em; | 15 | height: 20em; |
16 | display:none; | ||
16 | } | 17 | } |
17 | 18 | ||
18 | #courbe_warnings { | 19 | #courbe_warnings { |
@@ -22,3 +23,15 @@ body { | |||
22 | #courbe_erreurs { | 23 | #courbe_erreurs { |
23 | display: none; | 24 | display: none; |
24 | } | 25 | } |
26 | |||
27 | #import_donnees, #pref_graphique{ | ||
28 | display: none; | ||
29 | } | ||
30 | |||
31 | .bouton { | ||
32 | text-decoration: underline; | ||
33 | } | ||
34 | |||
35 | .bouton:hover { | ||
36 | cursor:pointer; | ||
37 | } | ||
diff --git a/templates/base.html b/templates/base.html index 9fa5263..694266c 100644 --- a/templates/base.html +++ b/templates/base.html | |||
@@ -33,7 +33,7 @@ | |||
33 | 33 | ||
34 | <nav><a href="/">Accueil et saisie des données</a> | | 34 | <nav><a href="/">Accueil et saisie des données</a> | |
35 | <a href="/apropos">À propos</a> | | 35 | <a href="/apropos">À propos</a> | |
36 | <a href="/faq">Foire Aux Questions</a> | | 36 | <a href="/faq">FAQ</a> | |
37 | <a href="/changelog">Changelog</a> | 37 | <a href="/changelog">Changelog</a> |
38 | </nav> | 38 | </nav> |
39 | 39 | ||
diff --git a/templates/changelog.html b/templates/changelog.html index 24447f6..7ba96cd 100644 --- a/templates/changelog.html +++ b/templates/changelog.html | |||
@@ -7,7 +7,8 @@ | |||
7 | <h3>{{ ligne[0] }}</h3> | 7 | <h3>{{ ligne[0] }}</h3> |
8 | <div class="date">Le {{ ligne[1] }}</div> | 8 | <div class="date">Le {{ ligne[1] }}</div> |
9 | 9 | ||
10 | <p>{{ ligne[2]|safe }}</p> | 10 | <div class="contenu_changelog"> |
11 | {{ ligne[2]|safe }} | ||
11 | </div> | 12 | </div> |
12 | {% endfor %} | 13 | {% endfor %} |
13 | 14 | ||
diff --git a/templates/faq.html b/templates/faq.html index 301f5d7..162f68d 100644 --- a/templates/faq.html +++ b/templates/faq.html | |||
@@ -1,6 +1,6 @@ | |||
1 | {% extends "base.html" %} | 1 | {% extends "base.html" %} |
2 | {% block contenu %} | 2 | {% block contenu %} |
3 | <h2>Foire Aux Questions</h2> | 3 | <h2>Foire Aux Questions (FAQ)</h2> |
4 | 4 | ||
5 | <div id="sommaire"> | 5 | <div id="sommaire"> |
6 | <ul>{% for cat in lcateg %} | 6 | <ul>{% for cat in lcateg %} |
diff --git a/templates/index.html b/templates/index.html index 23a9d36..60693d4 100644 --- a/templates/index.html +++ b/templates/index.html | |||
@@ -4,57 +4,42 @@ | |||
4 | <hr> | 4 | <hr> |
5 | 5 | ||
6 | 6 | ||
7 | <h2>Données du graphique</h2> | 7 | <h2>Données de l'enfant</h2> |
8 | 8 | ||
9 | <h3>Importer un fichier </h3> | ||
10 | <div class="bouton" onclick="affiche_cache('import_donnees',this)">Afficher</div> | ||
11 | <div id="import_donnees"> | ||
9 | <form action="/" method="post" enctype="multipart/form-data"> | 12 | <form action="/" method="post" enctype="multipart/form-data"> |
13 | |||
14 | |||
15 | |||
10 | <label for="fichier_donnees">Importer le fichier de données</label> | 16 | <label for="fichier_donnees">Importer le fichier de données</label> |
11 | <input type="file" name="fichier_donnees"> | 17 | <input type="file" name="fichier_donnees"> |
12 | <input type="submit" name="valider_fichier" value="Charger les données"> | 18 | <input type="submit" name="valider_fichier" value="Charger les données"> |
13 | </form> | 19 | </form> |
14 | 20 | </div> | |
21 | <hr> | ||
15 | 22 | ||
16 | <form id="donnees_enfant"> | 23 | <form id="donnees_enfant"> |
17 | 24 | ||
18 | 25 | <div> | |
26 | <input type="reset" value="Effacer les données du formulaire"> | ||
27 | </div> | ||
19 | 28 | ||
20 | <h3>Informations sur l'enfant</h3> | 29 | <h3>Informations sur l'enfant</h3> |
21 | <ul> | 30 | <ul> |
22 | <li><label>Nom de l'enfant :</label> <input type="text" name="nom" value="{{ valform.nom }}"></li> | 31 | <li><label>Nom de l'enfant :</label> <input type="text" name="nom" value="{{ valform.nom }}"></li> |
23 | <li><label>Sexe :</label> <input type="radio" name="sexe" value="F" {%if valform.sexe == "F" %}checked{% endif %}> féminin | 32 | <li><label>Sexe :</label> <input type="radio" name="sexe" value="F" {%if valform.sexe == "F" %}checked{% endif %}> féminin |
24 | | <input type="radio" name="sexe" value="M" {%if valform.sexe == "M"%} checked {% endif %}> masculin | <input type="radio" name="sexe" value="N" {%if valform.sexe == "N"%} checked {% endif %}> neutre (expérimental)</li> | 33 | | <input type="radio" name="sexe" value="M" {%if valform.sexe == "M"%} checked {% endif %}> masculin | <input type="radio" name="sexe" value="N" {%if valform.sexe == "N"%} checked {% endif %}> neutre (expérimental)</li> |
25 | <li><label>Date de naissance : </label> <input type="date" name="naissance" value="{{ valform.naissance }}"></li> | 34 | <li><label>Date de naissance : </label> <input type="date" name="naissance" value="{{ valform.naissance }}"></li> |
26 | </ul> | 35 | </ul> |
27 | 36 | ||
28 | 37 | ||
29 | <h3>Préférences du graphique</h3> | ||
30 | <ul> | ||
31 | <li><label>Type de courbe :</label> <input type="radio" name="typecourbe" value="P" | ||
32 | {% if valform.typecourbe == "P" or valform.typecourbe is not defined %} checked {% endif %}> Percentiles | <input type="radio" name="typecourbe" value="Z" | ||
33 | {% if valform.typecourbe == "Z" %} checked {% endif %}> Moyenne et écarts-type</li> | ||
34 | <li><label>Grille : </label><input type="checkbox" name="grille" {%if valform.grille == "oui" or valform.grille is not defined %} checked {% endif %}></li> | ||
35 | <li><label>Unité : </label> | ||
36 | <select name="unite"> | ||
37 | <option value="" {% if valform.typecourbe == "" or valform is not defined %} selected {%endif %}>Par défaut</option> | ||
38 | {% for unite in ['jours','semaines','mois','années'] %} | ||
39 | <option value="{{ unite }}"{% if valform.unite == unite %} selected {% endif %} >{{ unite }}</option> | ||
40 | {% endfor %} | ||
41 | </select></li> | ||
42 | <li><label>valeur maximum du graphique (facultatif, syntaxe similaire à l'âge, voir plus bas) </label><input type="text" name="maxi" value="{{ valform.maxi }}"></li> | ||
43 | <li>Dimensions du graphique : <label>largeur : </label><input type="text" name="largeur" value="{{ valform.largeur }}"> | ||
44 | <label>hauteur : </label><input type="text" name="hauteur" value="{{ valform.hauteur }}"></li> | ||
45 | <li><label>Légende : </label><input type="checkbox" name="legende" {% if valform.legende == 'oui' %} checked{% endif %}> | ||
46 | Position : <select name="positionlegende"> | ||
47 | {%for (pos,posnom) in [('upper left','Haut gauche'),('upper right','Haut Droite'),('lower left','Bas gauche'),('lower right','Bas droite')] %} | ||
48 | <option value="{{ pos }}">{{ posnom }}</option> | ||
49 | {% endfor %} | ||
50 | </select> | ||
51 | </li> | ||
52 | </ul> | ||
53 | 38 | ||
54 | 39 | ||
55 | 40 | ||
56 | <h3>Données de poids</h3> | 41 | <h3>Données de poids</h3> |
57 | <p>Syntaxe pour l'âge : utiliser j, s, m, a comme des "unités" (jours, semaines, mois, années). Vous pouvez mixer les unités, par exemple "3a2m5j" pour 3 ans, 2 mois et 5 jours. Les espaces sont ignorées, et il faut saisir des nombres entiers.</p> | 42 | <p>Syntaxe pour l'âge : utiliser j, s, m, a comme des "unités" (jours, semaines, mois, années). Vous pouvez mixer les unités, par exemple "3a2m5j" pour 3 ans, 2 mois et 5 jours. Les espaces sont ignorées, et il faut saisir des nombres entiers.</p> |
58 | <p>Saisir le poids en kilogrammes (par exemple "2.62" ou "2,62" pour 2 kilogrammes et 620 grammes).</p> | 43 | <p>Saisir le poids en kilogrammes (par exemple "2.62" ou "2,62" pour 2 kilogrammes et 620 grammes).</p> |
59 | <p>Il faut saisir la date ou l'âge. Si les deux sont saisis, seul l'âge comptera.</p> | 44 | <p>Il faut saisir la date ou l'âge. Si les deux sont saisis, seul l'âge comptera.</p> |
60 | 45 | ||
@@ -72,35 +57,70 @@ Position : <select name="positionlegende"> | |||
72 | {% endfor %} | 57 | {% endfor %} |
73 | 58 | ||
74 | </table> | 59 | </table> |
60 | <p class="bouton" onclick="ajoutelignes()">Cliquer ici pour ajouter des lignes</p> | ||
61 | |||
62 | |||
63 | |||
64 | <h3>Préférences du graphique</h3> | ||
65 | <div class="bouton" onclick="affiche_cache('pref_graphique',this)">Afficher</div> | ||
66 | |||
67 | <ul id="pref_graphique"> | ||
68 | <li><label>Type de courbe :</label> <input type="radio" name="typecourbe" value="P" | ||
69 | {% if valform.typecourbe == "P" or valform.typecourbe is not defined %} checked {% endif %}> Percentiles | <input type="radio" name="typecourbe" value="Z" | ||
70 | {% if valform.typecourbe == "Z" %} checked {% endif %}> Moyenne et écarts-type</li> | ||
71 | <li><label>Grille : </label><input type="checkbox" name="grille" {%if valform.grille == "oui" or valform.grille is not defined %} checked {% endif %}></li> | ||
72 | <li><label>Unité : </label> | ||
73 | <select name="unite"> | ||
74 | <option value="" {% if valform.typecourbe == "" or valform is not defined %} selected {%endif %}>Par défaut</option> | ||
75 | {% for unite in ['jours','semaines','mois','années'] %} | ||
76 | <option value="{{ unite }}"{% if valform.unite == unite %} selected {% endif %} >{{ unite }}</option> | ||
77 | {% endfor %} | ||
78 | </select></li> | ||
79 | <li><label>valeur maximum du graphique (facultatif, syntaxe similaire à l'âge, voir plus bas) </label><input type="text" name="maxi" value="{{ valform.maxi }}"></li> | ||
80 | <li>Dimensions du graphique : <label>largeur : </label><input type="text" name="largeur" value="{{ valform.largeur }}"> | ||
81 | <label>hauteur : </label><input type="text" name="hauteur" value="{{ valform.hauteur }}"></li> | ||
82 | <li><label>Légende : </label><input type="checkbox" name="legende" {% if valform.legende == 'oui' %} checked{% endif %}> | ||
83 | Position : <select name="positionlegende"> | ||
84 | {%for (pos,posnom) in [('upper left','Haut gauche'),('upper right','Haut Droite'),('lower left','Bas gauche'),('lower right','Bas droite')] %} | ||
85 | <option value="{{ pos }}">{{ posnom }}</option> | ||
86 | {% endfor %} | ||
87 | </select> | ||
88 | </li> | ||
89 | </ul> | ||
90 | |||
91 | |||
75 | </form> | 92 | </form> |
76 | <button onclick="ajoutelignes()">Ajouter des lignes</button> | ||
77 | 93 | ||
78 | <hr> | 94 | <hr> |
79 | 95 | ||
80 | <button onclick="appelle_image()">Je veux la courbe !</button> | 96 | <button onclick="appelle_image()">Je veux la courbe !</button> |
81 | 97 | ||
82 | |||
83 | <div id="sectioncourbe"> | ||
84 | <hr> | 98 | <hr> |
85 | <h2>Courbe</h2> | 99 | <div id="sectioncourbe"> |
86 | <img id="courbe"> | 100 | |
101 | <h2>Courbe</h2> | ||
102 | <img id="courbe"> | ||
103 | <div> | ||
104 | <button id="courbe_dl">Télécharger la courbe</button> | ||
105 | </div> | ||
87 | </div> | 106 | </div> |
88 | <div id="courbe_warnings"> | 107 | <div id="courbe_warnings"> |
89 | <p><strong>Alerte :</strong> la courbe a eu quelques soucis à se générer. Voici la liste des erreurs.</p> | 108 | <p><strong>Alerte :</strong> la courbe a eu quelques soucis à se générer. Voici la liste des erreurs.</p> |
90 | <ul></ul> | 109 | <ul></ul> |
91 | </div> | 110 | </div> |
92 | <div id="courbe_erreurs"> | 111 | <div id="courbe_erreurs"> |
93 | <p><strong>Alerte :</strong> La courbe n'a pas pu être générée. Vérifiez les données saisies, ou contactez l'administratrice. Erreurs : </p> | 112 | <p><strong>Alerte :</strong> La courbe n'a pas pu être générée. Vérifiez les données saisies, ou contactez l'administratrice. Erreurs : </p> |
94 | <ul></ul> | 113 | <ul></ul> |
95 | </div> | 114 | </div> |
96 | 115 | ||
97 | <div id="sectionexport"> | 116 | <div id="sectionexport"> |
98 | <h2>Export des données</h2> | 117 | <h2>Export des données</h2> |
99 | <p>Vous trouverez ci-dessous les données exportées au format texte. Il peut être utile de les copier/coller | 118 | <p>Vous pouvez télécharger les données afin de ne pas avoir à les re-saisir la prochaine fois.</p> |
100 | quelque part et de les sauvegarder, comme ça la prochaine fois vous n'aurez pas à ressaisir tout à la main.</p> | ||
101 | 119 | ||
102 | <textarea readonly id="export"> | 120 | <div><button id="export_dl">Télécharger les données</button></div> |
103 | </textarea> | 121 | <p>Si vous n'arrivez pas à télécharger les données, <a href='#export' onclick="affiche_export()">cliquez ici</a> pour les voir en texte clair : il vous suffira de les copier/coller dans un fichier texte.</p> |
122 | <textarea readonly id="export"> | ||
123 | </textarea> | ||
104 | 124 | ||
105 | </div> | 125 | </div> |
106 | 126 | ||