From 48b3a536373c1ee477fdff3e1f30bc3515d9e568 Mon Sep 17 00:00:00 2001 From: Benjamin Auder <benjamin.auder@somewhere> Date: Thu, 28 Dec 2017 15:00:06 +0100 Subject: [PATCH] Better README, write first draft of documentation --- .gitignore | 3 +- README.md | 11 ++- css/index.css | 4 +- doc/index.css | 15 ++++ doc/index.html | 66 ++++++++++++++++++ doc/index.pug | 75 ++++++++++++++++++++ index.html | 6 +- joueurs.sample.csv | 28 ++++++++ js/index.js | 168 ++++++++++++++++++++++----------------------- 9 files changed, 283 insertions(+), 93 deletions(-) create mode 100644 doc/index.css create mode 100644 doc/index.html create mode 100644 doc/index.pug create mode 100644 joueurs.sample.csv diff --git a/.gitignore b/.gitignore index ab6b7ea..524ce4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.swp -*.csv +/joueurs.csv +*.bak .~lock* diff --git a/README.md b/README.md index b9df387..edeb595 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ php >= 5.4 ## Ajustement du fichier de données 1. Renommer joueurs.csv.dist en joueurs.csv - 2. éditer joueurs.csv (ajout de joueurs, édition, suppression...). Format en lignes : prénom,nom[,pdt,session,présent] + 2. éditer joueurs.csv en s'inspirant de joueurs.sample.csv. Format en lignes : prénom,nom[,pdt,session,présent] pdt, session, présent : optionnels (par défaut resp. 0, 0, 1). @@ -20,8 +20,13 @@ pdt = "points de table" ; session = "mini-points" 1. Cliquer sur les joueurs absents dans l'onglet "joueurs" 2. Aller dans la section "appariements" et cliquer sur le bouton en haut - 3. À la fin d'une ronde, cliquer sur chaque table pour indiquer les (mini-)points. Pour lancer la ronde suivante, revenir en 1. + 3. Lancer le chrono (section "chronomètre", puis click gauche, puis passer en plein écran [F11]) + 4. À la fin d'une ronde, cliquer sur chaque table pour indiquer les (mini-)points. -Le classement est mis à jour dans la rubrique correspondante et dans joueurs.csv. Il peut être réinitialisé (bouton en haut). +Le classement est mis à jour dans la rubrique correspondante et dans joueurs.csv. Il peut être réinitialisé (bouton en haut). Après chaque opération sur les points, en cas d'erreur le bouton "Restaurer" en haut à droite annule la dernière opération. + +----- + +Pour plus de détails, naviguer vers localhost:8000/doc diff --git a/css/index.css b/css/index.css index 530cb4f..9afc23e 100644 --- a/css/index.css +++ b/css/index.css @@ -283,11 +283,11 @@ td.score { top: 0; min-height: 100%; width: 100%; - font-size: 500px; background-color: white; cursor: pointer; line-height: 100%; - font-family: monospace; + text-align: center; + vertical-align: middle; } .timeout { diff --git a/doc/index.css b/doc/index.css new file mode 100644 index 0000000..1bb5968 --- /dev/null +++ b/doc/index.css @@ -0,0 +1,15 @@ +@import '../vendor/Ubuntu_googlefont.css'; + +body { + font-family: Ubuntu, Verdana, sans-serif; + font-size: 1.1rem; + width: 1200px; + margin: 30px auto; + line-height: 1.5rem; +} + +img { + display: block; + margin: 30px 0; + width: 100%; +} diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..27bc7de --- /dev/null +++ b/doc/index.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Westcastle usage</title> + <link rel="stylesheet" href="doc/index.css"> + </head> + <body><span>L'application est divisée en 4 sections :</span> + <ul> + <li>Participants : la liste des joueurs présents (et absents)</li> + <li>Appariements : répartition des joueurs présents par tables</li> + <li>Chronomètre : un chrono qui démarre à 1h30 et sonne une fois à zéro</li> + <li>Classement : le tableau des scores (voir aussi joueurs.csv)</li> + </ul> + <h2>Participants</h2><img src="doc/screen_players.png"> + <p> + Un clic sur un joueur présent l'enlève des joueurs actifs (il est absent) ; + réciproquement, un clic sur un absent le ramène dans la liste des joueurs actifs. + Les appariements sont déterminés pour les joueurs présents seulement - en revanche le classement indique tout le monde. + + </p> + <h2>Appariements</h2><img src="doc/screen_pairings_new.png"> + <p> + Un clic sur le bouton "Nouvelle ronde" réinitialise toutes les tables, en (re-)répartissant les joueurs aléatoirement sur celles-ci. + Si nécessaire, un quatrième joueur "Toto" est ajouté en fin de table. + Si seulement 1, 2, ou 5 ou 6 joueurs sont présents, aucune configuration ne permet de faire jouer tout le monde : il y aura des joueurs exempts. + + </p><img src="doc/screen_pairings_scoring.png"> + <p> + En fin de ronde, un clic sur une table permet de donner les scores de chaque joueur - en mini-points. + Un clic sur "Enregistrer" valide les scores : le classement est automatiquement mis à jour dans la rubrique correspondante, + et la table s'affiche désormais sur fond vert. Un clic sur "Fermer" annule l'opération, aucun changement n'est effectué. + + </p><img src="doc/screen_pairings_restore.png"> + <p> + En cas d'erreur, ne surtout pas scorer une nouvelle table : d'abord restaurer l'état précédent en cliquant sur le bouton "Restaurer" + sur l'écran de classement ; alternativement, on peut cliquer sur le lien présent dans l'avertissement lorsqu'on reclique sur la table en question. + Ensuite, rentrer les scores corrigés. + + </p> + <h2>Chronomètre</h2><img src="doc/screen_timer.png"> + <p> + Ce chronomètre basique est conçu pour s'afficher centré en mode plein écran : il faut donc commencer par appuyer sur F11 + (la touche peut varier suivant le navigateur...). Ensuite : + + </p> + <ul> + <li>un clic gauche lance le chrono ou le met en pause. Un gong retentit une fois le temps écoulé.</li> + <li>un clic droit réinitialise le chrono (à 1h30 = 90 minutes)</li> + <li>un clic sur la croix en haut à droite revient à la section appariements (suite logique).</li> + </ul> + <p> + Note : le chronomètre reste actif même si l'on change de vue - penser à le mettre en pause ou le réinitialiser. + + </p> + <h2>Classement</h2><img src="doc/screen_ranking.png"> + <p> + Les scores sont ordonnés par points de table décroissants d'abord, puis en cas d'ex-aequos par mini-points décroissants. + + </p> + <p> + Un clic sur "Réinitialiser" remet tous les compteurs à zéro : par exemple pour démarrer un nouveau cycle de tournois. + Cette action peut être annulée (immédiatement après) en cliquant sur "Restaurer". + </p> + </body> +</html> \ No newline at end of file diff --git a/doc/index.pug b/doc/index.pug new file mode 100644 index 0000000..8e08c5e --- /dev/null +++ b/doc/index.pug @@ -0,0 +1,75 @@ +doctype html +html + + head + meta(charset="utf-8") + title Westcastle usage + link(rel="stylesheet", href="doc/index.css") + + body + + span L'application est divisée en 4 sections : + ul + li Participants : la liste des joueurs présents (et absents) + li Appariements : répartition des joueurs présents par tables + li Chronomètre : un chrono qui démarre à 1h30 et sonne une fois à zéro + li Classement : le tableau des scores (voir aussi joueurs.csv) + + h2 Participants + + img(src="doc/screen_players.png") + + p. + Un clic sur un joueur présent l'enlève des joueurs actifs (il est absent) ; + réciproquement, un clic sur un absent le ramène dans la liste des joueurs actifs. + Les appariements sont déterminés pour les joueurs présents seulement - en revanche le classement indique tout le monde. + + h2 Appariements + + img(src="doc/screen_pairings_new.png") + + p. + Un clic sur le bouton "Nouvelle ronde" réinitialise toutes les tables, en (re-)répartissant les joueurs aléatoirement sur celles-ci. + Si nécessaire, un quatrième joueur "Toto" est ajouté en fin de table. + Si seulement 1, 2, ou 5 ou 6 joueurs sont présents, aucune configuration ne permet de faire jouer tout le monde : il y aura des joueurs exempts. + + img(src="doc/screen_pairings_scoring.png") + + p. + En fin de ronde, un clic sur une table permet de donner les scores de chaque joueur - en mini-points. + Un clic sur "Enregistrer" valide les scores : le classement est automatiquement mis à jour dans la rubrique correspondante, + et la table s'affiche désormais sur fond vert. Un clic sur "Fermer" annule l'opération, aucun changement n'est effectué. + + img(src="doc/screen_pairings_restore.png") + + p. + En cas d'erreur, ne surtout pas scorer une nouvelle table : d'abord restaurer l'état précédent en cliquant sur le bouton "Restaurer" + sur l'écran de classement ; alternativement, on peut cliquer sur le lien présent dans l'avertissement lorsqu'on reclique sur la table en question. + Ensuite, rentrer les scores corrigés. + + h2 Chronomètre + + img(src="doc/screen_timer.png") + + p. + Ce chronomètre basique est conçu pour s'afficher centré en mode plein écran : il faut donc commencer par appuyer sur F11 + (la touche peut varier suivant le navigateur...). Ensuite : + + ul + li un clic gauche lance le chrono ou le met en pause. Un gong retentit une fois le temps écoulé. + li un clic droit réinitialise le chrono (à 1h30 = 90 minutes) + li un clic sur la croix en haut à droite revient à la section appariements (suite logique). + + p. + Note : le chronomètre reste actif même si l'on change de vue - penser à le mettre en pause ou le réinitialiser. + + h2 Classement + + img(src="doc/screen_ranking.png") + + p. + Les scores sont ordonnés par points de table décroissants d'abord, puis en cas d'ex-aequos par mini-points décroissants. + + p. + Un clic sur "Réinitialiser" remet tous les compteurs à zéro : par exemple pour démarrer un nouveau cycle de tournois. + Cette action peut être annulée (immédiatement après) en cliquant sur "Restaurer". diff --git a/index.html b/index.html index 5fc231b..c84fd64 100644 --- a/index.html +++ b/index.html @@ -12,18 +12,18 @@ <div id="mahjong"> <header> <ul class="sidenav"> - <li @click="display='players'">Joueurs</li> - <li @click="display='ranking'">Classement</li> + <li @click="display='players'">Participants</li> <li @click="display='pairings'">Appariements</li> <li @click="display='timer'">Chronomètre</li> + <li @click="display='ranking'">Classement</li> </ul> <img class="logo" src="img/logo_Westcastle.png"/> </header> <main> <my-players v-show="display=='players'" :players="players"></my-players> - <my-ranking v-show="display=='ranking'" :players="players" :sort-by-score="sortByScore" :write-score-to-db="writeScoreToDb"></my-ranking> <my-pairings v-show="display=='pairings'" :players="players" :write-score-to-db="writeScoreToDb"></my-pairings> <my-timer v-show="display=='timer'" @clockover="display='pairings'"></my-timer> + <my-ranking v-show="display=='ranking'" :players="players" :sort-by-score="sortByScore" :write-score-to-db="writeScoreToDb"></my-ranking> </main> </div> </body> diff --git a/joueurs.sample.csv b/joueurs.sample.csv new file mode 100644 index 0000000..5c62ea0 --- /dev/null +++ b/joueurs.sample.csv @@ -0,0 +1,28 @@ +prenom,nom,pdt,session,present +William,Plaisance,4,30,1 +Rosamonde,Dupuy,4,25,1 +Fabienne,Aubin,2,15,1 +Grégoire,Léveillé,2,10,0 +Fantina,Quinn,1,0,1 +Amitee,Morneau,1,-5,0 +William,Lespérance +Dreux,Vadeboncoeur +Brigliador,Cadieux +Grosvenor,Provencher +Landers,Devost +Joy,Laprise +Dielle,Séguin +Sidney,DeGrasse +Jules,Gaillou +Archaimbau,Bizier +Dexter,Aucoin +Searlas,Rivière +Germain,Charpie +Honore,Charlesbois +Georges,LaCaille +Anne,Ruest +Searlas,Rochefort +Ferrau,Adler +Aimée,Asselin +Delit,Cyr +Noël,Babin diff --git a/js/index.js b/js/index.js index 659a0dd..42a376e 100644 --- a/js/index.js +++ b/js/index.js @@ -45,88 +45,6 @@ new Vue({ }, }, }, - 'my-ranking': { - props: ['players','sortByScore','writeScoreToDb'], - template: ` - <div id="ranking"> - <table class="ranking"> - <tr class="title"> - <th>Rang</th> - <th>Joueur</th> - <th>Points</th> - <th>Mini-pts</th> - </tr> - <tr v-for="p in sortedPlayers"> - <td>{{ p.rank }}</td> - <td>{{ p.prenom }} {{ p.nom }}</td> - <td>{{ p.pdt }}</td> - <td>{{ p.session }}</td> - </tr> - </table> - <div class="button-container-vertical" style="width:200px"> - <button class="btn cancel" @click="resetPlayers()">Réinitialiser</button> - <button id="restoreBtn" class="btn" @click="restoreLast()">Restaurer</button> - </div> - </div> - `, - computed: { - sortedPlayers: function() { - let res = this.rankPeople(); - // Add rank information (taking care of ex-aequos) - let rank = 1; - for (let i=0; i<res.length; i++) - { - if (i==0 || this.sortByScore(res[i],res[i-1]) == 0) - res[i].rank = rank; - else //strictly lower scoring - res[i].rank = ++rank; - } - return res; - }, - }, - methods: { - rankPeople: function() { - return this.players - .slice(1) //discard Toto - .map( p => { return Object.assign({}, p); }) //to not alter original array - .sort(this.sortByScore); - }, - resetPlayers: function() { - this.players - .slice(1) //discard Toto - .forEach( p => { - p.pdt = 0; - p.session = 0; - p.available = 1; - }); - this.writeScoreToDb(); - document.getElementById("runPairing").click(); //TODO: hack... - }, - restoreLast: function() { - let xhr = new XMLHttpRequest(); - let self = this; - xhr.onreadystatechange = function() { - if (this.readyState == 4 && this.status == 200) - { - let players = JSON.parse(xhr.responseText); - if (players.length > 0) - { - players.unshift({ //add ghost 4th player for 3-players tables - prenom: "Toto", - nom: "", - pdt: 0, - session: 0, - available: 0, - }); - self.players = players; - } - } - }; - xhr.open("GET", "scripts/rw_players.php?restore=1", true); - xhr.send(null); - }, - }, - }, 'my-pairings': { props: ['players','writeScoreToDb'], data: function() { @@ -272,7 +190,7 @@ new Vue({ }; }, template: ` - <div id="timer"> + <div id="timer" :style="{lineHeight: screen.height+ 'px', fontSize: 0.66*screen.height + 'px'}"> <div @click.left="pauseResume()" @click.right.prevent="reset()" :class="{timeout:time==0}"> {{ formattedTime }} </div> @@ -299,7 +217,7 @@ new Vue({ }, reset: function(e) { this.running = false; - this.time = 10; //1:30 + this.time = 5400; //1:30 }, start: function() { if (!this.running) @@ -321,6 +239,88 @@ new Vue({ this.reset(); }, }, + 'my-ranking': { + props: ['players','sortByScore','writeScoreToDb'], + template: ` + <div id="ranking"> + <table class="ranking"> + <tr class="title"> + <th>Rang</th> + <th>Joueur</th> + <th>Points</th> + <th>Mini-pts</th> + </tr> + <tr v-for="p in sortedPlayers"> + <td>{{ p.rank }}</td> + <td>{{ p.prenom }} {{ p.nom }}</td> + <td>{{ p.pdt }}</td> + <td>{{ p.session }}</td> + </tr> + </table> + <div class="button-container-vertical" style="width:200px"> + <button class="btn cancel" @click="resetPlayers()">Réinitialiser</button> + <button id="restoreBtn" class="btn" @click="restoreLast()">Restaurer</button> + </div> + </div> + `, + computed: { + sortedPlayers: function() { + let res = this.rankPeople(); + // Add rank information (taking care of ex-aequos) + let rank = 1; + for (let i=0; i<res.length; i++) + { + if (i==0 || this.sortByScore(res[i],res[i-1]) == 0) + res[i].rank = rank; + else //strictly lower scoring + res[i].rank = ++rank; + } + return res; + }, + }, + methods: { + rankPeople: function() { + return this.players + .slice(1) //discard Toto + .map( p => { return Object.assign({}, p); }) //to not alter original array + .sort(this.sortByScore); + }, + resetPlayers: function() { + this.players + .slice(1) //discard Toto + .forEach( p => { + p.pdt = 0; + p.session = 0; + p.available = 1; + }); + this.writeScoreToDb(); + document.getElementById("runPairing").click(); //TODO: hack... + }, + restoreLast: function() { + let xhr = new XMLHttpRequest(); + let self = this; + xhr.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) + { + let players = JSON.parse(xhr.responseText); + if (players.length > 0) + { + players.unshift({ //add ghost 4th player for 3-players tables + prenom: "Toto", + nom: "", + pdt: 0, + session: 0, + available: 0, + }); + self.players = players; + } + } + }; + xhr.open("GET", "scripts/rw_players.php?restore=1", true); + xhr.send(null); + }, + }, + }, }, created: function() { let xhr = new XMLHttpRequest(); -- 2.44.0