Advance on client side
authorBenjamin Auder <benjamin.auder@somewhere>
Wed, 23 Jan 2019 15:33:21 +0000 (16:33 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Wed, 23 Jan 2019 15:33:21 +0000 (16:33 +0100)
94 files changed:
client/TODO [deleted file]
client/client_OLD/javascripts/contactForm.js [deleted file]
client/client_OLD/javascripts/data/challengeCheck.js [moved from client/client_OLD/javascripts/shared/challengeCheck.js with 100% similarity]
client/client_OLD/javascripts/data/nbPlayers.js [moved from client/client_OLD/javascripts/shared/nbPlayers.js with 100% similarity]
client/client_OLD/javascripts/data/userCheck.js [moved from client/client_OLD/javascripts/shared/userCheck.js with 100% similarity]
client/client_OLD/javascripts/utils/misc.js [deleted file]
client/client_OLD/javascripts/variant.js
client/client_OLD/views/app.pug
client/client_OLD/views/modals.pug [deleted file]
client/client_OLD/views/translations/en.pug [deleted file]
client/client_OLD/views/translations/es.pug [deleted file]
client/client_OLD/views/translations/fr.pug [deleted file]
client/client_OLD/views/welcome/en.pug [deleted file]
client/client_OLD/views/welcome/es.pug [deleted file]
client/client_OLD/views/welcome/fr.pug [deleted file]
client/package-lock.json
client/package.json
client/public/SOURCE [moved from server/favicon/SOURCE with 60% similarity]
client/public/index.html
client/src/App.vue
client/src/components/ContactForm.vue [new file with mode: 0644]
client/src/components/Language.vue [new file with mode: 0644]
client/src/components/Settings.vue [new file with mode: 0644]
client/src/main.js
client/src/modals/welcome/en.pug [new file with mode: 0644]
client/src/modals/welcome/es.pug [new file with mode: 0644]
client/src/modals/welcome/fr.pug [new file with mode: 0644]
client/src/rules/Alice/en.pug [moved from client/client_OLD/views/rules/Alice/en.pug with 100% similarity]
client/src/rules/Alice/es.pug [moved from client/client_OLD/views/rules/Alice/es.pug with 100% similarity]
client/src/rules/Alice/fr.pug [moved from client/client_OLD/views/rules/Alice/fr.pug with 100% similarity]
client/src/rules/Antiking/en.pug [moved from client/client_OLD/views/rules/Antiking/en.pug with 100% similarity]
client/src/rules/Antiking/es.pug [moved from client/client_OLD/views/rules/Antiking/es.pug with 100% similarity]
client/src/rules/Antiking/fr.pug [moved from client/client_OLD/views/rules/Antiking/fr.pug with 100% similarity]
client/src/rules/Atomic/en.pug [moved from client/client_OLD/views/rules/Atomic/en.pug with 100% similarity]
client/src/rules/Atomic/es.pug [moved from client/client_OLD/views/rules/Atomic/es.pug with 100% similarity]
client/src/rules/Atomic/fr.pug [moved from client/client_OLD/views/rules/Atomic/fr.pug with 100% similarity]
client/src/rules/Baroque/en.pug [moved from client/client_OLD/views/rules/Baroque/en.pug with 100% similarity]
client/src/rules/Baroque/fr.pug [moved from client/client_OLD/views/rules/Baroque/fr.pug with 100% similarity]
client/src/rules/Berolina/en.pug [moved from client/client_OLD/views/rules/Berolina/en.pug with 100% similarity]
client/src/rules/Berolina/fr.pug [moved from client/client_OLD/views/rules/Berolina/fr.pug with 100% similarity]
client/src/rules/Checkered/en.pug [moved from client/client_OLD/views/rules/Checkered/en.pug with 100% similarity]
client/src/rules/Checkered/fr.pug [moved from client/client_OLD/views/rules/Checkered/fr.pug with 100% similarity]
client/src/rules/Chess960/en.pug [moved from client/client_OLD/views/rules/Chess960/en.pug with 100% similarity]
client/src/rules/Chess960/fr.pug [moved from client/client_OLD/views/rules/Chess960/fr.pug with 100% similarity]
client/src/rules/Crazyhouse/en.pug [moved from client/client_OLD/views/rules/Crazyhouse/en.pug with 100% similarity]
client/src/rules/Crazyhouse/fr.pug [moved from client/client_OLD/views/rules/Crazyhouse/fr.pug with 100% similarity]
client/src/rules/Dark/en.pug [moved from client/client_OLD/views/rules/Dark/en.pug with 100% similarity]
client/src/rules/Dark/fr.pug [moved from client/client_OLD/views/rules/Dark/fr.pug with 100% similarity]
client/src/rules/Extinction/en.pug [moved from client/client_OLD/views/rules/Extinction/en.pug with 100% similarity]
client/src/rules/Extinction/fr.pug [moved from client/client_OLD/views/rules/Extinction/fr.pug with 100% similarity]
client/src/rules/Grand/en.pug [moved from client/client_OLD/views/rules/Grand/en.pug with 100% similarity]
client/src/rules/Grand/fr.pug [moved from client/client_OLD/views/rules/Grand/fr.pug with 100% similarity]
client/src/rules/Losers/en.pug [moved from client/client_OLD/views/rules/Losers/en.pug with 100% similarity]
client/src/rules/Losers/fr.pug [moved from client/client_OLD/views/rules/Losers/fr.pug with 100% similarity]
client/src/rules/Magnetic/en.pug [moved from client/client_OLD/views/rules/Magnetic/en.pug with 100% similarity]
client/src/rules/Magnetic/fr.pug [moved from client/client_OLD/views/rules/Magnetic/fr.pug with 100% similarity]
client/src/rules/Marseille/en.pug [moved from client/client_OLD/views/rules/Marseille/en.pug with 100% similarity]
client/src/rules/Marseille/fr.pug [moved from client/client_OLD/views/rules/Marseille/fr.pug with 100% similarity]
client/src/rules/Switching/en.pug [moved from client/client_OLD/views/rules/Switching/en.pug with 100% similarity]
client/src/rules/Switching/fr.pug [moved from client/client_OLD/views/rules/Switching/fr.pug with 100% similarity]
client/src/rules/Upsidedown/en.pug [moved from client/client_OLD/views/rules/Upsidedown/en.pug with 100% similarity]
client/src/rules/Upsidedown/fr.pug [moved from client/client_OLD/views/rules/Upsidedown/fr.pug with 100% similarity]
client/src/rules/Wildebeest/en.pug [moved from client/client_OLD/views/rules/Wildebeest/en.pug with 100% similarity]
client/src/rules/Wildebeest/fr.pug [moved from client/client_OLD/views/rules/Wildebeest/fr.pug with 100% similarity]
client/src/rules/Zen/en.pug [moved from client/client_OLD/views/rules/Zen/en.pug with 100% similarity]
client/src/rules/Zen/fr.pug [moved from client/client_OLD/views/rules/Zen/fr.pug with 100% similarity]
client/src/translations/en.js [new file with mode: 0644]
client/src/translations/es.js [new file with mode: 0644]
client/src/translations/fr.js [new file with mode: 0644]
client/src/utils/misc.js [new file with mode: 0644]
client/src/views/Home.vue
server/.gitignore
server/TODO [new file with mode: 0644]
server/app.js
server/config/parameters.js.dist
server/data/challengeCheck.js [deleted file]
server/data/nbPlayers.js [deleted file]
server/data/userCheck.js [deleted file]
server/favicon/android-chrome-192x192.png [deleted file]
server/favicon/android-chrome-512x512.png [deleted file]
server/favicon/apple-touch-icon.png [deleted file]
server/favicon/browserconfig.xml [deleted file]
server/favicon/favicon-16x16.png [deleted file]
server/favicon/favicon-32x32.png [deleted file]
server/favicon/favicon.ico [deleted file]
server/favicon/manifest.json [deleted file]
server/favicon/mstile-150x150.png [deleted file]
server/favicon/safari-pinned-tab.svg [deleted file]
server/models/Challenge.js
server/models/User.js
server/models/Variant.js
server/routes/challenges.js
server/routes/users.js
server/sockets.js

diff --git a/client/TODO b/client/TODO
deleted file mode 100644 (file)
index 5873270..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-En dev, faire tourner les deux serveurs 3000 et 8080, server + client
-En prod, client est statique ==> juste serveur, comme d'hab
-
-index.js ne va rien chercher sur serveur, pas même les trucs indispensables comme variant ou variantArray
-==> ils sont demandés au serveur en arrivant sur la page (avec Ã©ventuellement "Variant does not exist")
-
-https://alligator.io/vuejs/lazy-loading-vue-cli-3-webpack/
-https://webpack.js.org/guides/code-splitting/#dynamic-imports
-https://vue-loader.vuejs.org/guide/pre-processors.html#pug
-https://cli.vuejs.org/guide/webpack.html#simple-configuration
diff --git a/client/client_OLD/javascripts/contactForm.js b/client/client_OLD/javascripts/contactForm.js
deleted file mode 100644 (file)
index 8b1a079..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Note: not using Vue, but would be possible
-function trySendMessage()
-{
-       let email = document.getElementById("userEmail");
-       let subject = document.getElementById("mailSubject");
-       let content = document.getElementById("mailContent");
-       const error = checkNameEmail({email: email});
-       if (!!error)
-               return alert(error);
-       if (content.value.trim().length == 0)
-               return alert("Empty message");
-       if (subject.value.trim().length == 0 && !confirm("No subject. Send anyway?"))
-               return;
-
-       // Message sending:
-       ajax(
-               "/messages",
-               "POST",
-               {
-                       email: email.value,
-                       subject: subject.value,
-                       content: content.value,
-               },
-               () => {
-                       subject.value = "";
-                       content.value = "";
-                       let emailSent = document.getElementById("emailSent");
-                       emailSent.style.display = "inline-block";
-                       setTimeout(() => { emailSent.style.display = "none"; }, 2000);
-               }
-       );
-}
diff --git a/client/client_OLD/javascripts/utils/misc.js b/client/client_OLD/javascripts/utils/misc.js
deleted file mode 100644 (file)
index 287c0ea..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// Source: https://www.quirksmode.org/js/cookies.html
-function setCookie(name, value)
-{
-       var date = new Date();
-       date.setTime(date.getTime()+(183*24*60*60*1000)); //6 months
-       var expires = "; expires="+date.toGMTString();
-       document.cookie = name+"="+value+expires+"; path=/";
-}
-
-function getCookie(name, defaut) {
-       var nameEQ = name + "=";
-       var ca = document.cookie.split(';');
-       for (var i=0;i < ca.length;i++)
-       {
-               var c = ca[i];
-               while (c.charAt(0)==' ')
-                       c = c.substring(1,c.length);
-               if (c.indexOf(nameEQ) == 0)
-                       return c.substring(nameEQ.length,c.length);
-       }
-       return defaut; //cookie not found
-}
-
-// Random (enough) string for socket and game IDs
-function getRandString()
-{
-       return (Date.now().toString(36) + Math.random().toString(36).substr(2, 7))
-               .toUpperCase();
-}
-
-// Used both on index and variant page, to switch language
-function setLanguage(e)
-{
-       setCookie("lang", e.target.value);
-       location.reload(); //to include the right .pug file
-}
-
-// Shortcut for an often used click (on a modal)
-function doClick(elemId)
-{
-       document.getElementById(elemId).click(); //or ".checked = true"
-}
-
-function translate(msg)
-{
-       return translations[msg];
-}
index 5920c0c..c45de0a 100644 (file)
@@ -33,13 +33,6 @@ new Vue({
                this.conn.onclose = socketCloseListener;
        },
        methods: {
-               updateSettings: function(event) {
-                       const propName =
-                               event.target.id.substr(3).replace(/^\w/, c => c.toLowerCase())
-                       localStorage[propName] = ["highlight","coords"].includes(propName)
-                               ? event.target.checked
-                               : event.target.value;
-               },
                // Game is over, clear storage and put it in indexedDB
                archiveGame: function() {
                        // TODO: ...
index fb9853a..c246960 100644 (file)
@@ -1,60 +1,9 @@
 doctype html
 html
-
-       head
-               meta(charset="UTF-8")
-               title vchess - club
-               meta(name="viewport" content="width=device-width, initial-scale=1")
-               meta(name="msapplication-config"
-                       content="/images/favicon/browserconfig.xml")
-               meta(name="theme-color" content="#ffffff")
-               link(rel="stylesheet"
-                       href="//cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.0/mini-default.min.css")
-               link(rel="stylesheet"
-                       href="//fonts.googleapis.com/css?family=Open+Sans:400,700")
-               link(rel="apple-touch-icon" sizes="180x180"
-                       href="/images/favicon/apple-touch-icon.png")
-               link(rel="icon" type="image/png" sizes="32x32"
-                       href="/images/favicon/favicon-32x32.png")
-               link(rel="icon" type="image/png" sizes="16x16"
-                       href="/images/favicon/favicon-16x16.png")
-               link(rel="manifest" href="/images/favicon/manifest.json")
-               link(rel="mask-icon" href="/images/favicon/safari-pinned-tab.svg"
-                       color="#5bbad5")
-               link(rel="shortcut icon" href="/images/favicon/favicon.ico")
-               link(rel="stylesheet" href="/stylesheets/app.css")
-
-       // TODO: on-demand components, do not load all at startup
-       body
-               -
-                       var langName = {
-                               "en": "English",
-                               "es": "Español",
-                               "fr": "Français",
-                       };
-               case lang
-                       when "en"
-                               include translations/en
-                               include welcome/en
-                       when "es"
-                               include translations/es
-                               include welcome/es
-                       when "fr"
-                               include translations/fr
-                               include welcome/fr
-               include modals
                main#VueElement
                        my-upsert-user
                        .container
-                               // Header (on index only)
                                .row(v-show="display=='index'")
-                                       .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-                                               header
-                                                       img(src="/images/index/unicorn.svg")
-                                                       .info-container
-                                                               p vchess.club
-                                                       img(src="/images/index/wildebeest.svg")
-                               // Menu (top of page)
                                .row
                                        .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
                                                label.drawer-toggle(for="drawerControl")
diff --git a/client/client_OLD/views/modals.pug b/client/client_OLD/views/modals.pug
deleted file mode 100644 (file)
index e24a738..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-input#modalLang.modal(type="checkbox")
-div(role="dialog")
-       #language.card
-               label.modal-close(for="modalLang")
-               form
-                       fieldset
-                               label(for="langSelect")= translations["Language"]
-                               select#langSelect
-                                       each language,langCode in langName
-                                               option(value=langCode selected=(lang==langCode))
-                                                       =language
-
-input#modalSettings.modal(type="checkbox")
-div(role="dialog" aria-labelledby="settingsTitle")
-       .card.smallpad(@change="updateSettings")
-               label.modal-close(for="modalSettings")
-               h3#settingsTitle.section= translations["Preferences"]
-               fieldset
-                       label(for="setSqSize")= translations["Square size (in pixels). 0 for 'adaptative'"]
-                       input#setSqSize(type="number" v-model="settings.sqSize")
-               fieldset
-                       label(for="selectHints")= translations["Show move hints?"]
-                       select#setHints(v-model="settings.hints")
-                               option(value="0")= translations["None"]
-                               option(value="1")= translations["Moves from a square"]
-                               option(value="2")= translations["Pieces which can move"]
-               fieldset
-                       label(for="setHighlight")= translations["Highlight squares? (Last move & checks)"]
-                       input#setHighlight(type="checkbox" v-model="settings.highlight")
-               fieldset
-                       label(for="setCoords")= translations["Show board coordinates?"]
-                       input#setCoords(type="checkbox" v-model="settings.coords")
-               fieldset
-                       label(for="selectColor")= translations["Board colors"]
-                       select#setBcolor(v-model="settings.bcolor")
-                               option(value="lichess")
-                                       = translations["brown"]
-                               option(value="chesscom")
-                                       = translations["green"]
-                               option(value="chesstempo")
-                                       = translations["blue"]
-               fieldset
-                       label(for="selectSound")= translations["Play sounds?"]
-                       select#setSound(v-model="settings.sound")
-                               option(value="0")= translations["None"]
-                               option(value="1")= translations["New game"]
-                               option(value="2")= translations["All"]
-
-input#modalContact.modal(type="checkbox")
-div(role="dialog" aria-labelledby="contactTitle")
-       form.card.smallpad
-               label.modal-close(for="modalContact")
-               h3#contactTitle.section= translations["Contact form"]
-               fieldset
-                       label(for="userEmail")= translations["Email"]
-                       input#userEmail(type="email")
-               fieldset
-                       label(for="mailSubject")= translations["Subject"]
-                       input#mailSubject(type="text")
-               fieldset
-                       label(for="mailContent")= translations["Content"]
-                       br
-                       textarea#mailContent
-               fieldset
-                       button(type="button" onClick="trySendMessage()") Send
-                       p#emailSent= translations["Email sent!"]
diff --git a/client/client_OLD/views/translations/en.pug b/client/client_OLD/views/translations/en.pug
deleted file mode 100644 (file)
index 611236c..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
--
-       var translations =
-       {
-               "Language": "Language",
-               "Contact form": "Contact form",
-               "Email": "Email",
-               "Subject": "Subject",
-               "Content": "Content",
-               "Email sent!": "Email sent!",
-               "Hall": "Hall",
-               "My games": "My games",
-
-               // Index page:
-               "Help": "Help",
-               "First visit?": "First visit?",
-               ">>> Please read this <<<": ">>> Please read this <<<",
-               // Variants boxes:
-               "Both sides of the mirror": "Both sides of the mirror",
-               "Keep antiking in check": "Keep antiking in check",
-               "Explosive captures": "Explosive captures",
-               "Shared pieces": "Shared pieces",
-               "Standard rules": "Standard rules",
-               "Captures reborn": "Captures reborn",
-               "Capture all of a kind": "Capture all of a kind",
-               "Big board": "Big board",
-               "Lose all pieces": "Lose all pieces",
-               "Laws of attraction": "Laws of attraction",
-               "Exchange pieces positions": "Exchange pieces positions",
-               "Exotic captures": "Exotic captures",
-               "Balanced sliders & leapers": "Balanced sliders & leapers",
-               "Reverse captures": "Reverse captures",
-               "Pawns move diagonally": "Pawns move diagonally",
-               "In the shadow": "In the shadow",
-               "Move twice": "Move twice",
-               "Board upside down": "Board upside down",
-
-               // Variant page:
-               "New game": "New game",
-               "Waiting for opponent...": "Waiting for opponent...",
-               "Rules": "Rules",
-               "Play": "Play",
-               "Problems": "Problems",
-               "White win": "White win",
-               "Black win": "Black win",
-               "Draw": "Draw",
-               "New live game": "New live game",
-               "New game versus computer": "New game versus computer",
-               "Analysis mode": "Analysis mode",
-               "Start chat": "Start chat",
-               "Clear current game": "Clear current game",
-               "Settings": "Settings",
-               "Resign": "Resign",
-               "Undo": "Undo",
-               "Flip board": "Flip board",
-               "Game state (FEN):": "Game state (FEN):",
-               "Ok": "Ok",
-               "Random": "Random",
-               "Preferences": "Preferences",
-               "My name is...": "My name is...",
-               "Show hints?": "Show hints?",
-               "Board colors": "Board colors",
-               "brown": "brown",
-               "green": "green",
-               "blue": "blue",
-               "Play sounds?": "Play sounds?",
-               "None": "None",
-               "All": "All",
-               "Chat with ": "Chat with ",
-               "Type here": "Type here",
-               "Send": "Send",
-               "Download PGN": "Download PGN",
-               "Show solution": "Show solution",
-               "Load previous problems": "Load previous problems",
-               "Load next problems": "Load next problems",
-               "New": "New",
-               "Add a problem": "Add a problem",
-               "Full FEN description": "Full FEN description",
-               "Safe HTML tags allowed": "Safe HTML tags allowed",
-               "Instructions": "Instructions",
-               "Describe the problem goal": "Describe the problem goal",
-               "Solution": "Solution",
-               "How to solve the problem?": "How to solve the problem?",
-               "Preview": "Preview",
-               "Cancel": "Cancel",
-               "Solve": "Solve",
-               "Bad FEN description": "Bad FEN description",
-               "Empty instructions": "Empty instructions",
-               "Empty solution": "Empty solution",
-               "Already playing a game in this variant on another tab!":
-                       "Already playing a game in this variant on another tab!",
-               "Finish your ": "Finish your ",
-               " game first!": " game first!",
-               ": unfinished computer game will be erased":
-                       ": unfinished computer game will be erased",
-               ": current analysis will be erased":
-                       ": current analysis will be erased",
-       };
diff --git a/client/client_OLD/views/translations/es.pug b/client/client_OLD/views/translations/es.pug
deleted file mode 100644 (file)
index ce21966..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
--
-       var translations =
-       {
-               "Language": "Idioma",
-
-               // Index page:
-               "Help": "Ayuda",
-               "First visit?": "¿ Primera visita ?",
-               ">>> Please read this <<<": ">>> Por favor lee esto <<<",
-               // Variants boxes:
-               "Both sides of the mirror": "Ambos lados del espejo",
-               "Keep antiking in check": "Mantener el antirey en jaque",
-               "Explosive captures": "Capturas explosivas",
-               "Shared pieces": "Piezas compartidas",
-               "Standard rules": "Reglas estandar",
-               "Captures reborn": "Las capturas renacen",
-               "Capture all of a kind": "Capturar todo del mismo tipo",
-               "Big board": "Gran tablero",
-               "Lose all pieces": "Perder todas las piezas",
-               "Laws of attraction": "Las leyes de las atracciones",
-               "Exchange pieces positions": "Intercambiar las posiciones de las piezas",
-               "Exotic captures": "Capturas exóticas",
-               "Balanced sliders & leapers": "Modos de desplazamiento equilibrados",
-               "Reverse captures": "Capturas invertidas",
-               "Pawns move diagonally": "Peones se mueven en diagonal",
-               "In the shadow": "En la sombra",
-               "Move twice": "Mover dos veces",
-               "Board upside down": "Tablero al revés",
-
-               // Variant page:
-               "New game": "Nueva partida",
-               "Waiting for opponent...": "Esperando a un oponente...",
-               "Rules": "Reglas",
-               "Play": "Jugar",
-               "Problems": "Problemas",
-               "White win": "Las blancas ganan",
-               "Black win": "Las negras ganan",
-               "Draw": "Empate",
-               "New live game": "Nueva partida en vivo",
-               "New game versus computer": "Nueva partida contra la computadora",
-               "Analysis mode": "Modo de análisis",
-               "Start chat": "Iniciar chat",
-               "Clear current game": "Borrar la partida actual",
-               "Settings": "Ajustes",
-               "Resign": "Abandonar",
-               "Undo": "Deshacer",
-               "Flip board": "Girar el tablero",
-               "Game state (FEN):": "Estado del juego (FEN) :",
-               "Ok": "Ok",
-               "Random": "Aleatorio",
-               "Preferences": "Preferencias",
-               "My name is...": "Mi nombre es...",
-               "Show hints?": "Ayudas visuales ?",
-               "Board colors": "Colores del tablero",
-               "brown": "marrón",
-               "green": "verde",
-               "blue": "azul",
-               "Play sounds?": "¿ Tocar los sonidos ?",
-               "None": "No",
-               "All": "Todos",
-               "Chat with ": "Hablar con ",
-               "Type here": "Escribe aqui",
-               "Send": "Enviar",
-               "Download PGN": "Descargar el PGN",
-               "Show solution": "Mostrar la solucion",
-               "Load previous problems": "Cargar los problemas anteriores",
-               "Load next problems": "Cargar los siguientes problemas",
-               "New": "Nuevo",
-               "Add a problem": "Añadir un problema",
-               "Full FEN description": "Descripción FEN completa",
-               "Safe HTML tags allowed": "HTML 'seguro' autorizado",
-               "Instructions": "Instrucciones",
-               "Describe the problem goal": "Describe el objetivo del problema",
-               "Solution": "Solución",
-               "How to solve the problem?": "¿ Como resolver el problema ?",
-               "Preview": "Previsualizar",
-               "Cancel": "Anular",
-               "Solve": "Resolver",
-               "Bad FEN string": "Mala descripción FEN",
-               "Empty instructions": "Instrucciones vacias",
-               "Empty solution": "Solución vacía",
-               "Already playing a game in this variant on another tab!":
-                       "¡ Una partida está en progreso en esta variante en otra pestaña !",
-               "Finish your ": "¡ Termina tu ",
-               " game first!": " partida primero !",
-               ": unfinished computer game will be erased":
-                       " : una partida inconclusa contra la computadora será borrado",
-               ": current analysis will be erased":
-                       " : el análisis actual será borrado",
-       };
diff --git a/client/client_OLD/views/translations/fr.pug b/client/client_OLD/views/translations/fr.pug
deleted file mode 100644 (file)
index 3f3b1fe..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
--
-       var translations =
-       {
-               "Language": "Langue",
-
-               // Index page:
-               "Help": "Aide",
-               "First visit?": "Première visite ?",
-               ">>> Please read this <<<": ">>> SVP lisez ceci <<<",
-               // Variants boxes:
-               "Both sides of the mirror": "Les deux côté du miroir",
-               "Keep antiking in check": "Gardez l'antiroi en Ã©chec",
-               "Explosive captures": "Captures explosives",
-               "Shared pieces": "Pièces partagées",
-               "Standard rules": "Règles usuelles",
-               "Captures reborn": "Les captures renaissent",
-               "Capture all of a kind": "Capturez tout d'un même type",
-               "Big board": "Grand Ã©chiquier",
-               "Lose all pieces": "Perdez toutes les pièces",
-               "Laws of attraction": "Les lois de l'attraction",
-               "Exchange pieces positions": "Échangez les positions des pièces",
-               "Exotic captures": "Captures exotiques",
-               "Balanced sliders & leapers": "Modes de déplacement Ã©quilibrés",
-               "Reverse captures": "Captures inversées",
-               "Pawns move diagonally": "Les pions vont en diagonale",
-               "In the shadow": "Dans l'ombre",
-               "Move twice": "Jouer deux coups",
-               "Board upside down": "Échiquier Ã  l'envers",
-
-               // Variant page:
-               "New game": "Nouvelle partie",
-               "Waiting for opponent...": "En attente d'un adversaire...",
-               "Rules": "Règles",
-               "Play": "Jouer",
-               "Problems": "Problèmes",
-               "White win": "Les blancs gagnent",
-               "Black win": "Les noirs gagnent",
-               "Draw": "Match nul",
-               "New live game": "Nouvelle partie en direct",
-               "New game versus computer": "Nouvelle partie contre l'ordinateur",
-               "Analysis mode": "Mode analyse",
-               "Start chat": "Démarrer le chat",
-               "Clear current game": "Effacer la partie courante",
-               "Settings": "Réglages",
-               "Resign": "Abandonner",
-               "Undo": "Annuler",
-               "Flip board": "Tourner l'échiquier",
-               "Game state (FEN):": "État de la partie (FEN) :",
-               "Ok": "Ok",
-               "Random": "Aléatoire",
-               "Preferences": "Préférences",
-               "My name is...": "Je m'appelle...",
-               "Show hints?": "Aides visuelles ?",
-               "Board colors": "Couleurs de l'échiquier",
-               "brown": "marron",
-               "green": "vert",
-               "blue": "bleu",
-               "Play sounds?": "Jouer les sons ?",
-               "None": "Aucun",
-               "All": "Tous",
-               "Chat with ": "Discuter avec ",
-               "Type here": "Écrivez ici",
-               "Send": "Envoyer",
-               "Download PGN": "Télécharger le PGN",
-               "Show solution": "Montrer la solution",
-               "Load previous problems": "Charger les problèmes précédents",
-               "Load next problems": "Charger les problèmes suivants",
-               "New": "Nouveau",
-               "Add a problem": "Ajouter un problème",
-               "Full FEN description": "Description FEN complète",
-               "Safe HTML tags allowed": "HTML 'sûr' autorisé",
-               "Instructions": "Instructions",
-               "Describe the problem goal": "Décrire le but du problème",
-               "Solution": "Solution",
-               "How to solve the problem?": "Comment résoudre le problème ?",
-               "Preview": "Prévisualiser",
-               "Cancel": "Annuler",
-               "Solve": "Résoudre",
-               "Bad FEN string": "Mauvaise description FEN",
-               "Empty instructions": "Instructions vides",
-               "Empty solution": "Solution vide",
-               "Already playing a game in this variant on another tab!":
-                       "Une partie est en cours sur cette variante dans un autre onglet !",
-               "Finish your ": "Terminez votre ",
-               " game first!": " partie d'abord !",
-               ": unfinished computer game will be erased":
-                       " : une partie inachevée contre l'ordinateur sera effacée",
-               ": current analysis will be erased":
-                       " : l'analyse en cours sera effacée",
-       };
diff --git a/client/client_OLD/views/welcome/en.pug b/client/client_OLD/views/welcome/en.pug
deleted file mode 100644 (file)
index 06a9ca8..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-input#modalWelcome.modal(type="checkbox")
-div(role="dialog")
-       #welcome.card.text-center
-               label.modal-close(for="modalWelcome")
-               h3.blue.section Welcome to v[ariant]chess.club!
-               .section
-                       p A fun place to play chess variants in real time.
-                       p But wait... what is a chess variant?
-                       img(src="/images/Hexagonal_chess.svg")
-                       p.
-                               As suggested by the picture, a variant setup generally looks
-                               more or less like a chessboard with regular pieces
-                               (otherwise it's no longer a variant but a whole new game).
-                       p.emphasis.purple However...
-                       p Each variant has its own new rules, which can involve
-                       table.list-table
-                               tbody
-                                       tr
-                                               td * different pieces movements
-                                       tr
-                                               td * different chessboard(s)
-                                       tr
-                                               td * new pieces
-                                       tr
-                                               td * moves side effects
-                                       tr
-                                               td ...and so on
-               .section
-                       p.
-                               Example: imagine that a capture is an atomic explosion, wiping all
-                               adjacent squares &ndash; except the pawns, which as cockroaches can
-                               resist this kind of event.
-                       p Also state a goal: make the opponent's king explode.
-                       p &rarr; Congrats, you defined Atomic chess! (Playable here)
-               .section
-                       p.emphasis.purple
-                               | OK, this all sounds interesting, but why would that be fun?
-                       p.
-                               Because all games here start with a random setup: no more boring
-                               openings memorization, you have to rely on your chess skills only.
-                               No game is like another one.
-                       -
-                               var wikipediaUrl = "https://en.wikipedia.org/wiki/" +
-                                       "List_of_chess_variants#/media/File:Hexagonal_chess.svg";
-                       p.
-                               For informations about hundreds (if not thousands) of variants, you
-                               can visit the excellent
-                               #[a(href="https://www.chessvariants.com/") chessvariants] website.
-               p.smallfont Image credit: #[a(href=wikipediaUrl) Wikipedia]
diff --git a/client/client_OLD/views/welcome/es.pug b/client/client_OLD/views/welcome/es.pug
deleted file mode 100644 (file)
index 0c561bc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-input#modalWelcome.modal(type="checkbox")
-div(role="dialog")
-       #welcome.card.text-center
-               label.modal-close(for="modalWelcome")
-               h3.blue.section Â¡ Bienvenido a v[ariant]chess.club !
-               .section
-                       p Un sitio donde jugar variantes del juego de ajedrez en vivo.
-                       p Pero espera... Â¿ qué es una "variante" ?
-                       img(src="/images/Hexagonal_chess.svg")
-                       p.
-                               Como lo sugiere la imagen, el punto de inicio de una variante generalmente
-                               se ve como un tablero de ajedrez con las piezas habituales.
-                               (sino ya no es una variante, pero un nuevo juego).
-                       p.emphasis.purple Sin embargo...
-                       p Cada variante tiene sus propias reglas, que pueden definir
-                       table.list-table
-                               tbody
-                                       tr
-                                               td * diferentes desplazamientos de piezas
-                                       tr
-                                               td * differentes(s) tablero(s)
-                                       tr
-                                               td * nuevas piezas
-                                       tr
-                                               td * efectos de borde en los movimientos
-                                       tr
-                                               td ...etc
-               .section
-                       p.
-                               Ejemplo : Imagina que una captura es una explosión atómica que destruye
-                               todo en los 8 hexes cercanos, excepto los peones, que como las cucarachas
-                               se resisten a este tipo de cosas.
-                       p Define también un objetivo : hacer explotar al rey del adversario.
-                       p.
-                               &rarr; Â¡ Bien hecho, acabas de describir el ajedrez atómico !
-                               (Se puede jugar aquí)
-               .section
-                       p.emphasis.purple
-                               | OK, parece interesante, pero Â¿ por qué sería divertido ?!
-                       p.
-                               Como todas las partidas comienzan con una posición aleatoria :
-                               Â¡ terminadas las laboriosas memorizaciones de aperturas, puedes expresar
-                               tus habilidades de ajedrez desde el primer movimiento ! Ninguna partida
-                               es como otra.
-                       -
-                               var wikipediaUrl = "https://en.wikipedia.org/wiki/" +
-                                       "List_of_chess_variants#/media/File:Hexagonal_chess.svg";
-                       p.
-                               Pour s'informer sur des centaines de variantes (au moins), je vous invite Ã 
-                               visiter l'excellent site
-                               #[a(href="https://www.chessvariants.com/") chessvariants].
-               p.smallfont Credito de imagen : #[a(href=wikipediaUrl) Wikipedia]
diff --git a/client/client_OLD/views/welcome/fr.pug b/client/client_OLD/views/welcome/fr.pug
deleted file mode 100644 (file)
index d650a73..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-input#modalWelcome.modal(type="checkbox")
-div(role="dialog")
-       #welcome.card.text-center
-               label.modal-close(for="modalWelcome")
-               h3.blue.section Bienvenue sur v[ariant]chess.club!
-               .section
-                       p Un site où jouer Ã  des variantes du jeu d'échecs en direct.
-                       p Mais attendez... c'est quoi une "variante" ?
-                       img(src="/images/Hexagonal_chess.svg")
-                       p.
-                               Comme suggéré par l'image, le point de départ d'une variante
-                               ressemble en général Ã  un Ã©chiquier avec les pièces habituelles
-                               (sinon ce n'est plus une variante, mais un nouveau jeu).
-                       p.emphasis.purple Cependant...
-                       p Chaque variante a ses propres règles, qui peuvent définir
-                       table.list-table
-                               tbody
-                                       tr
-                                               td * différents déplacements de pièces
-                                       tr
-                                               td * différent(s) Ã©chiquier(s)
-                                       tr
-                                               td * de nouvelles pièces
-                                       tr
-                                               td * des effets de bord sur les coups
-                                       tr
-                                               td ...etc
-               .section
-                       p.
-                               Exemple: imaginez qu'une capture soit une explosion atomique,
-                               détruisant tout ce qui se trouve sur les 8 cases Ã  proximité &ndash;
-                               sauf les pions, qui tels les cafards résistent Ã  ce genre de truc.
-                       p Définissez Ã©galement un but : faire exploser le roi adverse.
-                       p &rarr; Bravo, vous venez de décrire les Ã©checs atomiques ! (Jouable ici)
-               .section
-                       p.emphasis.purple
-                               | OK Ã§a a l'air intéressant, mais pourquoi ce serait amusant ?!
-                       p.
-                               Car toutes les parties démarrent avec une position aléatoire : terminées
-                               les laborieuses mémorisations d'ouverture, vous pouvez exprimer vos talents
-                               Ã©chiquéens dès le premier coup ! Aucune partie ne ressemble Ã  une autre.
-                       -
-                               var wikipediaUrl = "https://en.wikipedia.org/wiki/" +
-                                       "List_of_chess_variants#/media/File:Hexagonal_chess.svg";
-                       p.
-                               Pour s'informer sur des centaines de variantes (au moins), je vous invite Ã 
-                               visiter l'excellent site
-                               #[a(href="https://www.chessvariants.com/") chessvariants].
-               p.smallfont Crédit image : #[a(href=wikipediaUrl) Wikipedia]
index 3a6f0fc..fe7eae3 100644 (file)
         }
       }
     },
+    "raw-loader": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-1.0.0.tgz",
+      "integrity": "sha512-Uqy5AqELpytJTRxYT4fhltcKPj0TyaEpzJDcGz7DFJi+pQOOi3GjR/DOdxTkTsF+NzhnldIoG6TORaBlInUuqA==",
+      "dev": true,
+      "requires": {
+        "loader-utils": "^1.1.0",
+        "schema-utils": "^1.0.0"
+      },
+      "dependencies": {
+        "ajv-keywords": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz",
+          "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
+          "dev": true
+        },
+        "schema-utils": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
+          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+          "dev": true,
+          "requires": {
+            "ajv": "^6.1.0",
+            "ajv-errors": "^1.0.0",
+            "ajv-keywords": "^3.1.0"
+          }
+        }
+      }
+    },
     "read-pkg": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz",
index a074534..7f51be9 100644 (file)
@@ -22,6 +22,7 @@
     "node-sass": "^4.9.0",
     "pug": "^2.0.3",
     "pug-plain-loader": "^1.0.0",
+    "raw-loader": "^1.0.0",
     "sass-loader": "^7.0.1",
     "vue-template-compiler": "^2.5.21"
   },
similarity index 60%
rename from server/favicon/SOURCE
rename to client/public/SOURCE
index 7d25d19..5565b45 100644 (file)
@@ -1,3 +1,2 @@
-Generated using https://realfavicongenerator.net/ ,
-with an image from here:
+Favicon image from here:
 https://www.freefavicon.com/freefavicons/objects/iconinfo/chess-piece-silhouette---red-king--rey-rojo-152-275290.html
index 0115e9f..6549d7a 100644 (file)
@@ -1,11 +1,15 @@
 <!DOCTYPE html>
-<html lang="en">
+<html>
   <head>
     <meta charset="utf-8">
                <title>vchess - club</title>
                <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+               <link rel="stylesheet"
+                       href="//cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.0/mini-default.min.css">
+               <link rel="stylesheet"
+                       href="//fonts.googleapis.com/css?family=Open+Sans:400,700">
   </head>
   <body>
     <div id="app"></div>
index 0199db2..1ece792 100644 (file)
@@ -1,14 +1,50 @@
 <template lang="pug">
-  #app
-    #nav
-      router-link(to="/") Home
-      | &nbsp;|&nbsp;
-      router-link(to="/about") About
-      | &nbsp;|&nbsp;
-      router-link(to="/test") Test
-    router-view
+#app
+  // modal "welcome" will be filled in the selected language
+  #modalWelcome
+  Language
+  Settings(:settings="settings")
+  ContactForm
+  .container
+    .row(v-show="$route.path == '/'")
+      // Header (on index only)
+      header
+        .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+          header
+            img(src="./assets/images/index/unicorn.svg")
+            .info-container
+              p vchess.club {{ $lang }}
+            img(src="./assets/images/index/wildebeest.svg")
+    .row
+      // Menu (top of page)
+      nav
+        router-link(to="/") Home
+        | &nbsp;|&nbsp;
+        router-link(to="/about") About
+        | &nbsp;|&nbsp;
+        router-link(to="/test") Test
+      router-view
 </template>
 
+<script>
+// See https://stackoverflow.com/a/35417159
+import ContactForm from "@/components/ContactForm.vue";
+import Language from "@/components/Language.vue";
+import Settings from "@/components/Settings.vue";
+export default {
+  data: function() {
+    return {
+      settings: {}, //TODO
+    };
+  },
+  components: {
+    ContactForm,
+    Language,
+    Settings,
+  },
+};
+</script>
+
 <style lang="sass">
 #app
   font-family: "Avenir", Helvetica, Arial, sans-serif
diff --git a/client/src/components/ContactForm.vue b/client/src/components/ContactForm.vue
new file mode 100644 (file)
index 0000000..cbfa622
--- /dev/null
@@ -0,0 +1,61 @@
+<template lang="pug">
+div
+  input#modalContact.modal(type="checkbox")
+  div(role="dialog" aria-labelledby="contactTitle")
+    form.card.smallpad
+      label.modal-close(for="modalContact")
+      h3#contactTitle.section {{ $tr["Contact form"] }}
+      fieldset
+        label(for="userEmail") {{ $tr["Email"] }}
+        input#userEmail(type="email")
+      fieldset
+        label(for="mailSubject") {{ $tr["Subject"] }}
+        input#mailSubject(type="text")
+      fieldset
+        label(for="mailContent") {{ $tr["Content"] }}
+        br
+        textarea#mailContent
+      fieldset
+        button(type="button" onClick="trySendMessage()") Send
+        p#emailSent {{ $tr["Email sent!"] }}
+</template>
+
+<script>
+import { ajax } from "../utils/ajax";
+export default {
+  name: "ContactForm",
+       methods: {
+               // Note: not using Vue here, but would be possible
+    trySendMessage: function() {
+      let email = document.getElementById("userEmail");
+      let subject = document.getElementById("mailSubject");
+      let content = document.getElementById("mailContent");
+      const error = checkNameEmail({email: email});
+      if (!!error)
+        return alert(error);
+      if (content.value.trim().length == 0)
+        return alert("Empty message");
+      if (subject.value.trim().length == 0 && !confirm("No subject. Send anyway?"))
+        return;
+
+      // Message sending:
+      ajax(
+        "/messages",
+        "POST",
+        {
+          email: email.value,
+          subject: subject.value,
+          content: content.value,
+        },
+        () => {
+          subject.value = "";
+          content.value = "";
+          let emailSent = document.getElementById("emailSent");
+          emailSent.style.display = "inline-block";
+          setTimeout(() => { emailSent.style.display = "none"; }, 2000);
+        }
+      );
+    },
+       },
+};
+</script>
diff --git a/client/src/components/Language.vue b/client/src/components/Language.vue
new file mode 100644 (file)
index 0000000..35c717f
--- /dev/null
@@ -0,0 +1,33 @@
+<template lang="pug">
+div
+  -
+    var langName = {
+      "en": "English",
+      "es": "Español",
+      "fr": "Français",
+    };
+  input#modalLang.modal(type="checkbox")
+  div(role="dialog")
+    #language.card
+      label.modal-close(for="modalLang")
+      form
+        fieldset
+          label(for="langSelect") {{ $tr["Language"] }}
+          select#langSelect
+            each language,langCode in langName
+              option(value=langCode selected=(lang==langCode))
+                =language
+</template>
+
+<script>
+export default {
+  name: "Language",
+       methods: {
+    // Used both on index and variant page, to switch language
+    setLanguage: function(e) {
+      localStorage["lang"] = e.target.value;
+      this.$lang = e.target.value;
+    },
+       },
+};
+</script>
diff --git a/client/src/components/Settings.vue b/client/src/components/Settings.vue
new file mode 100644 (file)
index 0000000..34431a5
--- /dev/null
@@ -0,0 +1,51 @@
+<template lang="pug">
+div
+  input#modalSettings.modal(type="checkbox")
+  div(role="dialog" aria-labelledby="settingsTitle")
+    .card.smallpad(@change="updateSettings")
+      label.modal-close(for="modalSettings")
+      h3#settingsTitle.section {{ $tr["Preferences"] }}
+      fieldset
+        label(for="setSqSize") {{ $tr["Square size (in pixels). 0 for 'adaptative'"] }}
+        input#setSqSize(type="number" v-model="settings.sqSize")
+      fieldset
+        label(for="selectHints") {{ $tr["Show move hints?"] }}
+        select#setHints(v-model="settings.hints")
+          option(value="0") {{ $tr["None"] }}
+          option(value="1") {{ $tr["Moves from a square"] }}
+          option(value="2") {{ $tr["Pieces which can move"] }}
+      fieldset
+        label(for="setHighlight") {{ $tr["Highlight squares? (Last move & checks)"] }}
+        input#setHighlight(type="checkbox" v-model="settings.highlight")
+      fieldset
+        label(for="setCoords") {{ $tr["Show board coordinates?"] }}
+        input#setCoords(type="checkbox" v-model="settings.coords")
+      fieldset
+        label(for="selectColor") {{ $tr["Board colors"] }}
+        select#setBcolor(v-model="settings.bcolor")
+          option(value="lichess") {{ $tr["brown"] }}
+          option(value="chesscom") {{ $tr["green"] }}
+          option(value="chesstempo") {{ $tr["blue"] }}
+      fieldset
+        label(for="selectSound") {{ $tr["Play sounds?"] }}
+        select#setSound(v-model="settings.sound")
+          option(value="0") {{ $tr["None"] }}
+          option(value="1") {{ $tr["New game"] }}
+          option(value="2") {{ $tr["All"] }}
+</template>
+
+<script>
+export default {
+  name: "Settings",
+  props: ["settings"],
+       methods: {
+    updateSettings: function(event) {
+      const propName =
+        event.target.id.substr(3).replace(/^\w/, c => c.toLowerCase())
+      localStorage[propName] = ["highlight","coords"].includes(propName)
+        ? event.target.checked
+        : event.target.value;
+    },
+       },
+};
+</script>
index e68447e..da3e602 100644 (file)
@@ -3,6 +3,7 @@ import App from "./App.vue";
 import router from "./router";
 import params from "./parameters"; //for socket connection
 import { ajax } from "./utils/ajax";
+import { util } from "./utils/misc";
 
 Vue.config.productionTip = false;
 
@@ -10,13 +11,30 @@ new Vue({
   router,
   render: function(h) {
     return h(App);
+  },
+//  data: {
+//    lang: "",
+//  },
+  watch: {
+    $lang: async function(newLang) {
+      // Fill modalWelcome, and import translations from "./translations/$lang.js"
+      document.getElementById("modalWelcome").innerHTML =
+        require("raw-loader!pug-plain-loader!./modals/welcome/" + newLang + ".pug");
+      const tModule = await import("./translations/" + newLang + ".js");
+      Vue.prototype.$tr = tModule.translations;
+      //console.log(tModule.translations);
+    },
   },
        created: function() {
-               //alert("test");
+    const supportedLangs = ["en","es","fr"];
+    Vue.prototype.$lang = localStorage["lang"] ||
+      supportedLangs.includes(navigator.language)
+        ? navigator.language
+        : "en";
                ajax("/variants", "GET", res => {
                        Vue.prototype.$variants = res.variantArray;
                });
-               Vue.prototype.$conn = null; //TODO
+    Vue.prototype.$tr = {}; //to avoid a compiler error
                const myid = localStorage["myid"] || util.getRandString();
                // NOTE: in this version, we don't say on which page we are, yet
                // ==> we'll say "enter/leave" page XY (in fact juste "enter", seemingly)
diff --git a/client/src/modals/welcome/en.pug b/client/src/modals/welcome/en.pug
new file mode 100644 (file)
index 0000000..c4ceabc
--- /dev/null
@@ -0,0 +1,49 @@
+input#modalWelcome.modal(type="checkbox")
+div(role="dialog")
+  #welcome.card.text-center
+    label.modal-close(for="modalWelcome")
+    h3.blue.section Welcome to v[ariant]chess.club!
+    .section
+      p A fun place to play chess variants in real time.
+      p But wait... what is a chess variant?
+      img(src="/images/Hexagonal_chess.svg")
+      p.
+        As suggested by the picture, a variant setup generally looks more or less
+        like a chessboard with regular pieces (otherwise it's no longer a variant
+        but a whole new game).
+      p.emphasis.purple However...
+      p Each variant has its own new rules, which can involve
+      table.list-table
+        tbody
+          tr
+            td * different pieces movements
+          tr
+            td * different chessboard(s)
+          tr
+            td * new pieces
+          tr
+            td * moves side effects
+          tr
+            td ...and so on
+    .section
+      p.
+        Example: imagine that a capture is an atomic explosion, wiping all
+        adjacent squares &ndash; except the pawns, which as cockroaches can
+        resist this kind of event.
+      p Also state a goal: make the opponent's king explode.
+      p &rarr; Congrats, you defined Atomic chess! (Playable here)
+    .section
+      p.emphasis.purple
+        | OK, this all sounds interesting, but why would that be fun?
+      p.
+        Because all games here start with a random setup: no more boring
+        openings memorization, you have to rely on your chess skills only.
+        No game is like another one.
+      -
+        var wikipediaUrl = "https://en.wikipedia.org/wiki/" +
+          "List_of_chess_variants#/media/File:Hexagonal_chess.svg";
+      p.
+        For informations about hundreds (if not thousands) of variants, you
+        can visit the excellent
+        #[a(href="https://www.chessvariants.com/") chessvariants] website.
+    p.smallfont Image credit: #[a(href=wikipediaUrl) Wikipedia]
diff --git a/client/src/modals/welcome/es.pug b/client/src/modals/welcome/es.pug
new file mode 100644 (file)
index 0000000..1efba98
--- /dev/null
@@ -0,0 +1,35 @@
+input#modalWelcome.modal(type="checkbox")
+div(role="dialog")
+  #welcome.card.text-center
+    label.modal-close(for="modalWelcome")
+    h3.blue.section Â¡ Bienvenido a v[ariant]chess.club !
+    .section
+      p Un sitio donde jugar variantes del juego de ajedrez en vivo.
+      p Pero espera... Â¿ qué es una "variante" ?
+      img(src="/images/Hexagonal_chess.svg")
+      p Como lo sugiere la imagen, el punto de inicio de una variante generalmente se ve como un tablero de ajedrez con las piezas habituales (sino ya no es una variante, pero un nuevo juego).
+      p.emphasis.purple Sin embargo...
+      p Cada variante tiene sus propias reglas, que pueden definir
+      table.list-table
+        tbody
+          tr
+            td * diferentes desplazamientos de piezas
+          tr
+            td * differentes(s) tablero(s)
+          tr
+            td * nuevas piezas
+          tr
+            td * efectos de borde en los movimientos
+          tr
+            td ...etc
+    .section
+      p Ejemplo : Imagina que una captura es una explosión atómica que destruye todo en los 8 hexes cercanos, excepto los peones, que como las cucarachas se resisten a este tipo de cosas.
+      p Define también un objetivo : hacer explotar al rey del adversario.
+      p &rarr; Â¡ Bien hecho, acabas de describir el ajedrez atómico ! (Se puede jugar aquí)
+    .section
+      p.emphasis.purple
+        | OK, parece interesante, pero Â¿ por qué sería divertido ?!
+      p Como todas las partidas comienzan con una posición aleatoria : Â¡ terminadas las laboriosas memorizaciones de aperturas, puedes expresar tus habilidades de ajedrez desde el primer movimiento ! Ninguna partida es como otra.
+      p Para conocer cientos de variantes (al menos), te invito a visitar el excelente sitio
+      a(href="https://www.chessvariants.com/" target="_blank" rel="noopener") chessvariants.
+    p.smallfont Credito de imagen : #[a(href="https://en.wikipedia.org/wiki/List_of_chess_variants#/media/File:Hexagonal_chess.svg") Wikipedia]
diff --git a/client/src/modals/welcome/fr.pug b/client/src/modals/welcome/fr.pug
new file mode 100644 (file)
index 0000000..819dbcc
--- /dev/null
@@ -0,0 +1,40 @@
+input#modalWelcome.modal(type="checkbox")
+div(role="dialog")
+  #welcome.card.text-center
+    label.modal-close(for="modalWelcome")
+    h3.blue.section Bienvenue sur v[ariant]chess.club!
+    .section
+      p Un site où jouer Ã  des variantes du jeu d'échecs en direct.
+      p Mais attendez... c'est quoi une "variante" ?
+      img(src="/images/Hexagonal_chess.svg")
+      p Comme suggéré par l'image, le point de départ d'une variante ressemble en général Ã  un Ã©chiquier avec les pièces habituelles (sinon ce n'est plus une variante, mais un nouveau jeu).
+      p.emphasis.purple Cependant...
+      p Chaque variante a ses propres règles, qui peuvent définir
+      table.list-table
+        tbody
+          tr
+            td * différents déplacements de pièces
+          tr
+            td * différent(s) Ã©chiquier(s)
+          tr
+            td * de nouvelles pièces
+          tr
+            td * des effets de bord sur les coups
+          tr
+            td ...etc
+    .section
+      p Exemple: imaginez qu'une capture soit une explosion atomique, détruisant tout ce qui se trouve sur les 8 cases Ã  proximité &ndash; sauf les pions, qui tels les cafards résistent Ã  ce genre de truc.
+      p Définissez Ã©galement un but : faire exploser le roi adverse.
+      p &rarr; Bravo, vous venez de décrire les Ã©checs atomiques ! (Jouable ici)
+    .section
+      p.emphasis.purple
+        | OK Ã§a a l'air intéressant, mais pourquoi ce serait amusant ?!
+      p Car toutes les parties démarrent avec une position aléatoire : terminées les laborieuses mémorisations d'ouverture, vous pouvez exprimer vos talents Ã©chiquéens dès le premier coup ! Aucune partie ne ressemble Ã  une autre.
+      -
+        var wikipediaUrl = "https://en.wikipedia.org/wiki/" +
+          "List_of_chess_variants#/media/File:Hexagonal_chess.svg";
+      p.
+        Pour s'informer sur des centaines de variantes (au moins), je vous invite Ã 
+        visiter l'excellent site
+        #[a(href="https://www.chessvariants.com/") chessvariants].
+    p.smallfont Crédit image : #[a(href=wikipediaUrl) Wikipedia]
diff --git a/client/src/translations/en.js b/client/src/translations/en.js
new file mode 100644 (file)
index 0000000..6f7cab1
--- /dev/null
@@ -0,0 +1,96 @@
+export const translations =
+{
+  "Language": "Language",
+  "Contact form": "Contact form",
+  "Email": "Email",
+  "Subject": "Subject",
+  "Content": "Content",
+  "Email sent!": "Email sent!",
+  "Hall": "Hall",
+  "My games": "My games",
+
+  // Index page:
+  "Help": "Help",
+  "First visit?": "First visit?",
+  ">>> Please read this <<<": ">>> Please read this <<<",
+  // Variants boxes:
+  "Both sides of the mirror": "Both sides of the mirror",
+  "Keep antiking in check": "Keep antiking in check",
+  "Explosive captures": "Explosive captures",
+  "Shared pieces": "Shared pieces",
+  "Standard rules": "Standard rules",
+  "Captures reborn": "Captures reborn",
+  "Capture all of a kind": "Capture all of a kind",
+  "Big board": "Big board",
+  "Lose all pieces": "Lose all pieces",
+  "Laws of attraction": "Laws of attraction",
+  "Exchange pieces positions": "Exchange pieces positions",
+  "Exotic captures": "Exotic captures",
+  "Balanced sliders & leapers": "Balanced sliders & leapers",
+  "Reverse captures": "Reverse captures",
+  "Pawns move diagonally": "Pawns move diagonally",
+  "In the shadow": "In the shadow",
+  "Move twice": "Move twice",
+  "Board upside down": "Board upside down",
+
+  // Variant page:
+  "New game": "New game",
+  "Waiting for opponent...": "Waiting for opponent...",
+  "Rules": "Rules",
+  "Play": "Play",
+  "Problems": "Problems",
+  "White win": "White win",
+  "Black win": "Black win",
+  "Draw": "Draw",
+  "New live game": "New live game",
+  "New game versus computer": "New game versus computer",
+  "Analysis mode": "Analysis mode",
+  "Start chat": "Start chat",
+  "Clear current game": "Clear current game",
+  "Settings": "Settings",
+  "Resign": "Resign",
+  "Undo": "Undo",
+  "Flip board": "Flip board",
+  "Game state (FEN):": "Game state (FEN):",
+  "Ok": "Ok",
+  "Random": "Random",
+  "Preferences": "Preferences",
+  "My name is...": "My name is...",
+  "Show hints?": "Show hints?",
+  "Board colors": "Board colors",
+  "brown": "brown",
+  "green": "green",
+  "blue": "blue",
+  "Play sounds?": "Play sounds?",
+  "None": "None",
+  "All": "All",
+  "Chat with ": "Chat with ",
+  "Type here": "Type here",
+  "Send": "Send",
+  "Download PGN": "Download PGN",
+  "Show solution": "Show solution",
+  "Load previous problems": "Load previous problems",
+  "Load next problems": "Load next problems",
+  "New": "New",
+  "Add a problem": "Add a problem",
+  "Full FEN description": "Full FEN description",
+  "Safe HTML tags allowed": "Safe HTML tags allowed",
+  "Instructions": "Instructions",
+  "Describe the problem goal": "Describe the problem goal",
+  "Solution": "Solution",
+  "How to solve the problem?": "How to solve the problem?",
+  "Preview": "Preview",
+  "Cancel": "Cancel",
+  "Solve": "Solve",
+  "Bad FEN description": "Bad FEN description",
+  "Empty instructions": "Empty instructions",
+  "Empty solution": "Empty solution",
+  "Already playing a game in this variant on another tab!":
+    "Already playing a game in this variant on another tab!",
+  "Finish your ": "Finish your ",
+  " game first!": " game first!",
+  ": unfinished computer game will be erased":
+    ": unfinished computer game will be erased",
+  ": current analysis will be erased":
+    ": current analysis will be erased",
+};
diff --git a/client/src/translations/es.js b/client/src/translations/es.js
new file mode 100644 (file)
index 0000000..e348218
--- /dev/null
@@ -0,0 +1,89 @@
+export const translations =
+{
+  "Language": "Idioma",
+
+  // Index page:
+  "Help": "Ayuda",
+  "First visit?": "¿ Primera visita ?",
+  ">>> Please read this <<<": ">>> Por favor lee esto <<<",
+  // Variants boxes:
+  "Both sides of the mirror": "Ambos lados del espejo",
+  "Keep antiking in check": "Mantener el antirey en jaque",
+  "Explosive captures": "Capturas explosivas",
+  "Shared pieces": "Piezas compartidas",
+  "Standard rules": "Reglas estandar",
+  "Captures reborn": "Las capturas renacen",
+  "Capture all of a kind": "Capturar todo del mismo tipo",
+  "Big board": "Gran tablero",
+  "Lose all pieces": "Perder todas las piezas",
+  "Laws of attraction": "Las leyes de las atracciones",
+  "Exchange pieces positions": "Intercambiar las posiciones de las piezas",
+  "Exotic captures": "Capturas exóticas",
+  "Balanced sliders & leapers": "Modos de desplazamiento equilibrados",
+  "Reverse captures": "Capturas invertidas",
+  "Pawns move diagonally": "Peones se mueven en diagonal",
+  "In the shadow": "En la sombra",
+  "Move twice": "Mover dos veces",
+  "Board upside down": "Tablero al revés",
+
+  // Variant page:
+  "New game": "Nueva partida",
+  "Waiting for opponent...": "Esperando a un oponente...",
+  "Rules": "Reglas",
+  "Play": "Jugar",
+  "Problems": "Problemas",
+  "White win": "Las blancas ganan",
+  "Black win": "Las negras ganan",
+  "Draw": "Empate",
+  "New live game": "Nueva partida en vivo",
+  "New game versus computer": "Nueva partida contra la computadora",
+  "Analysis mode": "Modo de análisis",
+  "Start chat": "Iniciar chat",
+  "Clear current game": "Borrar la partida actual",
+  "Settings": "Ajustes",
+  "Resign": "Abandonar",
+  "Undo": "Deshacer",
+  "Flip board": "Girar el tablero",
+  "Game state (FEN):": "Estado del juego (FEN) :",
+  "Ok": "Ok",
+  "Random": "Aleatorio",
+  "Preferences": "Preferencias",
+  "My name is...": "Mi nombre es...",
+  "Show hints?": "Ayudas visuales ?",
+  "Board colors": "Colores del tablero",
+  "brown": "marrón",
+  "green": "verde",
+  "blue": "azul",
+  "Play sounds?": "¿ Tocar los sonidos ?",
+  "None": "No",
+  "All": "Todos",
+  "Chat with ": "Hablar con ",
+  "Type here": "Escribe aqui",
+  "Send": "Enviar",
+  "Download PGN": "Descargar el PGN",
+  "Show solution": "Mostrar la solucion",
+  "Load previous problems": "Cargar los problemas anteriores",
+  "Load next problems": "Cargar los siguientes problemas",
+  "New": "Nuevo",
+  "Add a problem": "Añadir un problema",
+  "Full FEN description": "Descripción FEN completa",
+  "Safe HTML tags allowed": "HTML 'seguro' autorizado",
+  "Instructions": "Instrucciones",
+  "Describe the problem goal": "Describe el objetivo del problema",
+  "Solution": "Solución",
+  "How to solve the problem?": "¿ Como resolver el problema ?",
+  "Preview": "Previsualizar",
+  "Cancel": "Anular",
+  "Solve": "Resolver",
+  "Bad FEN string": "Mala descripción FEN",
+  "Empty instructions": "Instrucciones vacias",
+  "Empty solution": "Solución vacía",
+  "Already playing a game in this variant on another tab!":
+    "¡ Una partida está en progreso en esta variante en otra pestaña !",
+  "Finish your ": "¡ Termina tu ",
+  " game first!": " partida primero !",
+  ": unfinished computer game will be erased":
+    " : una partida inconclusa contra la computadora será borrado",
+  ": current analysis will be erased":
+    " : el análisis actual será borrado",
+};
diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js
new file mode 100644 (file)
index 0000000..ee65449
--- /dev/null
@@ -0,0 +1,89 @@
+export const translations =
+{
+  "Language": "Langue",
+
+  // Index page:
+  "Help": "Aide",
+  "First visit?": "Première visite ?",
+  ">>> Please read this <<<": ">>> SVP lisez ceci <<<",
+  // Variants boxes:
+  "Both sides of the mirror": "Les deux côté du miroir",
+  "Keep antiking in check": "Gardez l'antiroi en Ã©chec",
+  "Explosive captures": "Captures explosives",
+  "Shared pieces": "Pièces partagées",
+  "Standard rules": "Règles usuelles",
+  "Captures reborn": "Les captures renaissent",
+  "Capture all of a kind": "Capturez tout d'un même type",
+  "Big board": "Grand Ã©chiquier",
+  "Lose all pieces": "Perdez toutes les pièces",
+  "Laws of attraction": "Les lois de l'attraction",
+  "Exchange pieces positions": "Échangez les positions des pièces",
+  "Exotic captures": "Captures exotiques",
+  "Balanced sliders & leapers": "Modes de déplacement Ã©quilibrés",
+  "Reverse captures": "Captures inversées",
+  "Pawns move diagonally": "Les pions vont en diagonale",
+  "In the shadow": "Dans l'ombre",
+  "Move twice": "Jouer deux coups",
+  "Board upside down": "Échiquier Ã  l'envers",
+
+  // Variant page:
+  "New game": "Nouvelle partie",
+  "Waiting for opponent...": "En attente d'un adversaire...",
+  "Rules": "Règles",
+  "Play": "Jouer",
+  "Problems": "Problèmes",
+  "White win": "Les blancs gagnent",
+  "Black win": "Les noirs gagnent",
+  "Draw": "Match nul",
+  "New live game": "Nouvelle partie en direct",
+  "New game versus computer": "Nouvelle partie contre l'ordinateur",
+  "Analysis mode": "Mode analyse",
+  "Start chat": "Démarrer le chat",
+  "Clear current game": "Effacer la partie courante",
+  "Settings": "Réglages",
+  "Resign": "Abandonner",
+  "Undo": "Annuler",
+  "Flip board": "Tourner l'échiquier",
+  "Game state (FEN):": "État de la partie (FEN) :",
+  "Ok": "Ok",
+  "Random": "Aléatoire",
+  "Preferences": "Préférences",
+  "My name is...": "Je m'appelle...",
+  "Show hints?": "Aides visuelles ?",
+  "Board colors": "Couleurs de l'échiquier",
+  "brown": "marron",
+  "green": "vert",
+  "blue": "bleu",
+  "Play sounds?": "Jouer les sons ?",
+  "None": "Aucun",
+  "All": "Tous",
+  "Chat with ": "Discuter avec ",
+  "Type here": "Écrivez ici",
+  "Send": "Envoyer",
+  "Download PGN": "Télécharger le PGN",
+  "Show solution": "Montrer la solution",
+  "Load previous problems": "Charger les problèmes précédents",
+  "Load next problems": "Charger les problèmes suivants",
+  "New": "Nouveau",
+  "Add a problem": "Ajouter un problème",
+  "Full FEN description": "Description FEN complète",
+  "Safe HTML tags allowed": "HTML 'sûr' autorisé",
+  "Instructions": "Instructions",
+  "Describe the problem goal": "Décrire le but du problème",
+  "Solution": "Solution",
+  "How to solve the problem?": "Comment résoudre le problème ?",
+  "Preview": "Prévisualiser",
+  "Cancel": "Annuler",
+  "Solve": "Résoudre",
+  "Bad FEN string": "Mauvaise description FEN",
+  "Empty instructions": "Instructions vides",
+  "Empty solution": "Solution vide",
+  "Already playing a game in this variant on another tab!":
+    "Une partie est en cours sur cette variante dans un autre onglet !",
+  "Finish your ": "Terminez votre ",
+  " game first!": " partie d'abord !",
+  ": unfinished computer game will be erased":
+    " : une partie inachevée contre l'ordinateur sera effacée",
+  ": current analysis will be erased":
+    " : l'analyse en cours sera effacée",
+};
diff --git a/client/src/utils/misc.js b/client/src/utils/misc.js
new file mode 100644 (file)
index 0000000..178f3cf
--- /dev/null
@@ -0,0 +1,43 @@
+export const util =
+{
+  // Source: https://www.quirksmode.org/js/cookies.html
+  setCookie: function(name, value)
+  {
+    var date = new Date();
+    date.setTime(date.getTime()+(183*24*60*60*1000)); //6 months
+    var expires = "; expires="+date.toGMTString();
+    document.cookie = name+"="+value+expires+"; path=/";
+  },
+
+  getCookie: function(name, defaut) {
+    var nameEQ = name + "=";
+    var ca = document.cookie.split(';');
+    for (var i=0;i < ca.length;i++)
+    {
+      var c = ca[i];
+      while (c.charAt(0)==' ')
+        c = c.substring(1,c.length);
+      if (c.indexOf(nameEQ) == 0)
+        return c.substring(nameEQ.length,c.length);
+    }
+    return defaut; //cookie not found
+  },
+
+  // Random (enough) string for socket and game IDs
+  getRandString: function()
+  {
+    return (Date.now().toString(36) + Math.random().toString(36).substr(2, 7))
+      .toUpperCase();
+  },
+
+  // Shortcut for an often used click (on a modal)
+  doClick: function(elemId)
+  {
+    document.getElementById(elemId).click(); //or ".checked = true"
+  },
+
+  translate: function(msg)
+  {
+    return translations[msg];
+  },
+};
index 156976c..de83b09 100644 (file)
@@ -12,7 +12,7 @@ import HelloWorld from "@/components/HelloWorld.vue";
 export default {
   name: "home",
   components: {
-    HelloWorld
+    HelloWorld,
   }
 };
 </script>
index 20ffe9f..aeb7c87 100644 (file)
@@ -18,7 +18,7 @@ pids
 # Various files
 /db/vchess.sqlite
 /config/parameters.js
-/serve/
+/static/
 
 # Compiled binary addons (https://nodejs.org/api/addons.html)
 build/Release
diff --git a/server/TODO b/server/TODO
new file mode 100644 (file)
index 0000000..bcffc7b
--- /dev/null
@@ -0,0 +1,9 @@
+Later: use http2
+https://webapplog.com/http2-node/
+https://www.npmjs.com/package/spdy
+Express 5?
+
+Finish :
+ - models
+ - routes
+ - sockets
index aa8cade..b1aee52 100644 (file)
@@ -7,7 +7,7 @@ var favicon = require('serve-favicon');
 
 var app = express();
 
-app.use(favicon(path.join(__dirname, "favicon", "favicon.ico")));
+app.use(favicon(path.join(__dirname, "static", "favicon.ico")));
 
 if (app.get('env') === 'development')
 {
@@ -27,13 +27,13 @@ else
 app.use(express.json());
 app.use(express.urlencoded({ extended: false }));
 app.use(cookieParser());
-app.use(express.static(path.join(__dirname, 'serve'))); //client "prod" files
+app.use(express.static(path.join(__dirname, 'static'))); //client "prod" files
 
 // In development stage the client side has its own server
-if (app.get('env') === 'development')
+if (params.cors.enable)
 {
        app.use(function(req, res, next) {
-               res.header("Access-Control-Allow-Origin", "*");
+               res.header("Access-Control-Allow-Origin", params.cors.allowedOrigin);
                res.header("Access-Control-Allow-Headers",
                        "Origin, X-Requested-With, Content-Type, Accept");
                next();
index 6f274dd..0beabed 100644 (file)
@@ -5,6 +5,12 @@ module.exports =
 
        // To know in which environment the code run
        env: process.env.NODE_ENV || 'development',
+       
+       // CORS: cross-origin resource sharing options
+       cors: {
+               enable: Parameters.env === "development",
+               allowedOrigin: "*",
+       },
 
        // Lifespan of a (login) cookie
        cookieExpire: 183*24*60*60*1000, //6 months in milliseconds
diff --git a/server/data/challengeCheck.js b/server/data/challengeCheck.js
deleted file mode 100644 (file)
index 459396a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-function checkChallenge(c)
-{
-       const vid = parseInt(c.vid);
-       if (isNaN(vid) || vid <= 0)
-               return "Please select a variant";
-
-       const mainTime = parseInt(c.mainTime);
-       const increment = parseInt(c.increment);
-       if (isNaN(mainTime) || mainTime <= 0)
-               return "Main time should be strictly positive";
-       if (isNaN(increment) || increment < 0)
-               return "Increment must be positive";
-
-       // Basic alphanumeric check for players names
-       let playerCount = 0;
-       for (p of c.players)
-       {
-               if (p.name.length > 0)
-               {
-                       if (!p.name.match(/^[\w]+$/))
-                               return "Wrong characters in players names";
-                       playerCount++;
-               }
-       }
-
-       if (playerCount > 0 && playerCount != c.nbPlayers-1)
-               return "None, or all of the opponent names must be filled"
-
-       // Just characters check on server:
-       if (!c.fen.match(/^[a-zA-Z0-9, /-]*$/))
-               return "Bad FEN string";
-}
-
-module.exports = checkChallenge;
diff --git a/server/data/nbPlayers.js b/server/data/nbPlayers.js
deleted file mode 100644 (file)
index 3b41a94..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-const NbPlayers =
-{
-       "Alice": [2,3,4],
-       "Antiking": [2,3,4],
-       "Atomic": [2,3,4],
-       "Baroque": [2,3,4],
-       "Berolina": [2,4],
-       "Checkered": [2,3,4],
-       "Chess960": [2,3,4],
-       "Crazyhouse": [2,3,4],
-       "Dark": [2,3,4],
-       "Extinction": [2,3,4],
-       "Grand": [2],
-       "Losers": [2,3,4],
-       "Magnetic": [2],
-       "Marseille": [2],
-       "Switching": [2,3,4],
-       "Upsidedown": [2],
-       "Wildebeest": [2],
-       "Zen": [2,3,4],
-};
-
-module.exports = NbPlayers;
diff --git a/server/data/userCheck.js b/server/data/userCheck.js
deleted file mode 100644 (file)
index 9c46b2a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-function checkNameEmail(o)
-{
-       if (typeof o.name === "string")
-       {
-               if (o.name.length == 0)
-                       return "Empty name";
-               if (!o.name.match(/^[\w]+$/))
-                       return "Bad characters in name";
-       }
-       if (typeof o.email === "string")
-       {
-               if (o.email.length == 0)
-                       return "Empty email";
-               if (!o.email.match(/^[\w.+-]+@[\w.+-]+$/))
-                       return "Bad characters in email";
-       }
-}
-
-module.exports = checkNameEmail;
diff --git a/server/favicon/android-chrome-192x192.png b/server/favicon/android-chrome-192x192.png
deleted file mode 100644 (file)
index 727630a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat 9249f7ccb03573152b1210b27c244462ac286aea                12108
diff --git a/server/favicon/android-chrome-512x512.png b/server/favicon/android-chrome-512x512.png
deleted file mode 100644 (file)
index bd462bb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat 510e77fc0cd116eb8ef2e8743718f4c1c22393ec                33049
diff --git a/server/favicon/apple-touch-icon.png b/server/favicon/apple-touch-icon.png
deleted file mode 100644 (file)
index 1b453ab..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat 60b73e04ab8fc7a125745cbdc8f6f5cb298c105f                12621
diff --git a/server/favicon/browserconfig.xml b/server/favicon/browserconfig.xml
deleted file mode 100644 (file)
index bb8e477..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<browserconfig>
-    <msapplication>
-        <tile>
-                                       <square150x150logo src="/images/favicon/mstile-150x150.png"/>
-            <TileColor>#da532c</TileColor>
-        </tile>
-    </msapplication>
-</browserconfig>
diff --git a/server/favicon/favicon-16x16.png b/server/favicon/favicon-16x16.png
deleted file mode 100644 (file)
index b334454..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat 10c5fd36c2cb305a3f7e6a6f39eccba03a679087                  995
diff --git a/server/favicon/favicon-32x32.png b/server/favicon/favicon-32x32.png
deleted file mode 100644 (file)
index 386456d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat 53091595a131897b202391f3f0ffaa61f283c56a                 1877
diff --git a/server/favicon/favicon.ico b/server/favicon/favicon.ico
deleted file mode 100644 (file)
index 75bd50b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat c12f062ae7f59219c96acae47fafca862cb035a2                15086
diff --git a/server/favicon/manifest.json b/server/favicon/manifest.json
deleted file mode 100644 (file)
index e967fc5..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "name": "",
-    "icons": [
-        {
-            "src": "/images/favicon/android-chrome-192x192.png",
-            "sizes": "192x192",
-            "type": "image/png"
-        },
-        {
-            "src": "/images/favicon/android-chrome-512x512.png",
-            "sizes": "512x512",
-            "type": "image/png"
-        }
-    ],
-    "theme_color": "#ffffff",
-    "background_color": "#ffffff",
-    "display": "standalone"
-}
diff --git a/server/favicon/mstile-150x150.png b/server/favicon/mstile-150x150.png
deleted file mode 100644 (file)
index 928fe05..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#$# git-fat fc323034e5b15647a98909a7cce05bb80eecef93                 5784
diff --git a/server/favicon/safari-pinned-tab.svg b/server/favicon/safari-pinned-tab.svg
deleted file mode 100644 (file)
index da1d457..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
- "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
-<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
- width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
- preserveAspectRatio="xMidYMid meet">
-<metadata>
-Created by potrace 1.11, written by Peter Selinger 2001-2013
-</metadata>
-<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
-fill="#000000" stroke="none">
-<path d="M2379 4963 c-1 -10 -2 -85 -3 -168 l-1 -150 -160 0 -160 0 -3 -168
--2 -167 47 -1 c27 0 100 -1 163 -2 l115 -2 1 -173 0 -173 -35 -33 c-120 -110
--227 -244 -237 -296 0 -3 -6 -25 -13 -49 -23 -82 -40 -186 -42 -269 -2 -93 -8
--132 -19 -132 -4 0 -74 36 -156 80 -81 44 -149 80 -150 80 -1 0 -19 8 -40 17
--22 9 -41 17 -44 18 -3 0 -10 3 -16 7 -15 10 -160 46 -219 54 -72 10 -300 12
--365 2 -153 -23 -378 -121 -489 -213 -52 -43 -136 -133 -176 -190 -180 -252
--206 -530 -74 -805 84 -176 177 -292 453 -565 l213 -210 2 -190 c5 -364 17
--639 32 -711 7 -39 19 -60 47 -86 44 -40 123 -86 207 -121 117 -47 100 -41
-140 -52 17 -4 35 -10 40 -14 6 -3 15 -6 20 -7 6 -1 37 -10 70 -19 76 -21 161
--42 200 -49 17 -2 41 -7 55 -10 58 -13 77 -16 120 -21 25 -3 56 -7 70 -10 69
--14 250 -20 585 -20 390 0 553 8 665 31 14 3 39 7 55 9 17 1 55 8 85 15 30 6
-69 14 85 17 17 2 71 16 120 30 50 14 97 27 105 28 8 2 16 4 18 5 1 2 5 3 10 5
-4 1 16 5 27 9 11 4 52 19 90 33 87 32 202 94 242 130 31 28 55 65 60 93 9 54
-14 122 18 240 2 74 7 225 11 335 3 110 7 230 8 267 l2 67 65 62 c35 33 120
-116 187 182 419 413 559 725 470 1047 -7 25 -13 47 -14 50 0 3 -6 19 -13 35
--131 321 -408 538 -766 602 -22 4 -110 7 -195 7 -169 -1 -273 -17 -395 -62
--64 -24 -205 -93 -231 -113 -26 -21 -175 -91 -181 -85 -4 3 -8 43 -9 89 -4
-209 -38 342 -116 455 -16 23 -73 86 -125 139 l-96 96 1 141 c0 78 1 156 1 173
-l1 33 161 -2 c106 -1 163 2 167 9 5 9 8 298 3 323 -1 3 -75 5 -166 5 l-165 -1
--1 30 c0 17 -1 93 -1 169 l0 137 -179 0 c-163 0 -179 -2 -180 -17z m285 -1203
-c98 -44 194 -185 213 -311 10 -63 9 -189 -1 -271 -11 -87 -57 -214 -151 -415
--24 -50 -46 -101 -50 -112 -3 -12 -10 -21 -15 -21 -4 0 -11 -11 -14 -25 -10
--39 -77 -146 -89 -142 -12 4 -107 174 -101 180 3 2 -2 10 -11 17 -8 7 -15 16
--15 21 0 5 -16 44 -36 86 -91 199 -139 329 -149 405 -11 85 -8 279 5 328 35
-129 126 240 228 276 49 17 128 11 186 -16z m-1245 -490 c100 -19 209 -55 257
--87 16 -10 31 -17 34 -16 17 8 196 -123 288 -211 154 -146 325 -411 387 -596
-36 -110 60 -213 70 -305 3 -27 8 -70 11 -95 11 -97 7 -281 -7 -295 -18 -17
--116 -30 -304 -40 -148 -8 -318 -22 -380 -31 -135 -19 -170 -26 -377 -72 -133
--30 -161 -25 -260 44 -140 99 -238 185 -420 367 -258 260 -330 401 -331 647 0
-132 11 176 71 299 41 83 246 281 290 281 6 0 12 4 14 8 6 16 170 87 228 99 14
-2 43 8 65 12 69 14 263 9 364 -9z m2661 7 c76 -18 119 -31 150 -44 270 -115
-439 -297 490 -527 10 -47 14 -191 6 -248 -16 -113 -88 -259 -181 -368 -39 -46
--321 -328 -360 -360 -17 -14 -55 -45 -85 -70 -30 -25 -57 -47 -60 -50 -3 -3
--39 -27 -80 -55 -72 -48 -78 -50 -142 -49 -37 1 -75 5 -85 9 -20 9 -25 10 -68
-19 -16 3 -50 10 -75 15 -170 38 -291 54 -480 66 -155 9 -321 22 -385 30 -11 1
--28 3 -37 4 -42 3 -47 23 -43 190 2 88 6 167 8 178 3 10 8 41 11 68 34 306
-240 683 501 912 193 170 375 257 586 279 35 3 66 8 68 10 6 6 232 -3 261 -9z
-m-909 -2041 c176 -9 246 -19 383 -53 247 -60 370 -151 296 -218 -26 -23 -75
--21 -230 10 -134 27 -284 54 -340 60 -19 2 -53 6 -75 9 -22 3 -69 8 -105 11
--36 4 -83 8 -105 10 -228 22 -667 22 -880 0 -22 -2 -69 -7 -105 -10 -104 -10
--216 -24 -240 -30 -8 -2 -35 -7 -60 -10 -25 -4 -112 -20 -195 -36 -188 -38
--218 -39 -248 -8 -13 13 -22 30 -21 37 1 6 2 16 3 22 2 20 58 63 118 91 65 31
-245 79 353 94 67 9 136 14 265 21 72 3 131 7 133 8 4 5 960 -3 1053 -8z m-381
--371 c125 -7 306 -22 360 -30 14 -2 48 -6 75 -10 28 -3 66 -9 85 -11 74 -10
-248 -46 315 -66 85 -24 204 -80 228 -106 33 -37 28 -89 -11 -118 -14 -10 -97
-3 -197 30 -5 2 -28 7 -50 11 -49 11 -47 10 -65 17 -8 4 -69 18 -135 32 -107
-22 -155 31 -286 50 -92 14 -269 20 -549 21 -361 0 -509 -9 -700 -44 -30 -6
--66 -12 -80 -15 -14 -2 -81 -18 -150 -36 -69 -17 -134 -33 -145 -35 -11 -3
--59 -13 -107 -24 l-87 -19 -20 22 c-11 11 -23 33 -26 48 -19 75 164 162 450
-214 41 7 161 26 195 30 19 2 50 6 69 9 18 3 68 8 110 10 42 3 92 7 111 10 19
-2 87 7 150 11 63 3 116 7 118 9 4 4 223 -2 342 -10z"/>
-<path d="M2525 3631 c-31 -13 -71 -58 -93 -104 -36 -77 -44 -226 -17 -344 3
--13 7 -33 10 -44 17 -78 85 -227 117 -256 19 -17 20 -17 35 2 32 42 94 183
-114 260 20 79 29 235 17 300 -16 82 -60 155 -110 181 -30 16 -44 16 -73 5z"/>
-<path d="M1197 3094 c-1 -1 -31 -4 -67 -7 -97 -9 -223 -49 -282 -89 -14 -10
--29 -18 -32 -18 -34 0 -206 -193 -206 -231 0 -5 -4 -17 -9 -27 -39 -71 -51
--165 -31 -241 13 -52 81 -192 118 -241 64 -87 236 -266 369 -387 48 -43 101
--91 118 -107 58 -54 74 -58 177 -41 51 8 104 17 118 20 14 3 41 8 60 11 19 3
-80 14 135 24 117 21 143 26 310 51 44 6 91 13 105 14 113 14 139 17 169 19 20
-1 37 10 43 20 22 39 -19 225 -92 416 -96 254 -210 452 -319 552 -166 154 -387
-249 -604 260 -42 3 -78 3 -80 2z"/>
-<path d="M3858 3095 c-2 -1 -34 -5 -73 -8 -68 -6 -144 -21 -175 -34 -8 -3 -20
--7 -25 -8 -23 -5 -121 -49 -135 -60 -8 -7 -25 -16 -37 -19 -13 -4 -23 -12 -23
--17 0 -5 -7 -9 -15 -9 -8 0 -15 -4 -15 -10 0 -5 -5 -10 -11 -10 -6 0 -17 -6
--24 -12 -8 -7 -44 -40 -80 -73 -82 -73 -139 -152 -198 -270 -59 -120 -87 -182
--87 -194 0 -6 -4 -11 -10 -11 -5 0 -10 -9 -10 -19 0 -11 -4 -23 -10 -26 -5 -3
--10 -13 -10 -22 0 -8 -6 -29 -14 -46 -37 -82 -85 -266 -86 -327 -1 -58 3 -70
-19 -71 9 -1 27 -2 41 -4 14 -2 52 -6 85 -10 33 -3 71 -8 85 -10 14 -3 43 -7
-65 -10 64 -10 84 -13 190 -30 55 -9 109 -18 120 -19 21 -3 126 -23 319 -62 66
--13 125 -20 132 -16 53 30 475 446 546 539 123 159 158 294 113 438 -42 135
--126 248 -239 320 -73 47 -215 93 -307 101 -41 3 -86 7 -101 9 -15 2 -28 2
--30 0z"/>
-</g>
-</svg>
index 96db0a2..e1fb448 100644 (file)
@@ -18,6 +18,39 @@ var db = require("../utils/database");
 
 const ChallengeModel =
 {
+       checkChallenge: function(c)
+       {
+               const vid = parseInt(c.vid);
+               if (isNaN(vid) || vid <= 0)
+                       return "Please select a variant";
+
+               const mainTime = parseInt(c.mainTime);
+               const increment = parseInt(c.increment);
+               if (isNaN(mainTime) || mainTime <= 0)
+                       return "Main time should be strictly positive";
+               if (isNaN(increment) || increment < 0)
+                       return "Increment must be positive";
+
+               // Basic alphanumeric check for players names
+               let playerCount = 0;
+               for (p of c.players)
+               {
+                       if (p.name.length > 0)
+                       {
+                               if (!p.name.match(/^[\w]+$/))
+                                       return "Wrong characters in players names";
+                               playerCount++;
+                       }
+               }
+
+               if (playerCount > 0 && playerCount != c.nbPlayers-1)
+                       return "None, or all of the opponent names must be filled"
+
+               // Just characters check on server:
+               if (!c.fen.match(/^[a-zA-Z0-9, /-]*$/))
+                       return "Bad FEN string";
+       },
+
        // fen cannot be undefined; TODO: generate fen on server instead
        create: function(c, cb)
        {
index a36ab68..cf4c529 100644 (file)
@@ -16,6 +16,24 @@ var params = require("../config/parameters");
 
 const UserModel =
 {
+       checkNameEmail: function(o)
+       {
+               if (typeof o.name === "string")
+               {
+                       if (o.name.length == 0)
+                               return "Empty name";
+                       if (!o.name.match(/^[\w]+$/))
+                               return "Bad characters in name";
+               }
+               if (typeof o.email === "string")
+               {
+                       if (o.email.length == 0)
+                               return "Empty email";
+                       if (!o.email.match(/^[\w.+-]+@[\w.+-]+$/))
+                               return "Bad characters in email";
+               }
+       },
+
        // NOTE: parameters are already cleaned (in controller), thus no sanitization here
        create: function(name, email, notify, callback)
        {
index 233d938..ae41793 100644 (file)
@@ -9,6 +9,29 @@ var db = require("../utils/database");
 
 const VariantModel =
 {
+       // This is duplicated in client. TODO: really required here?
+       NbPlayers:
+       {
+               "Alice": [2,3,4],
+               "Antiking": [2,3,4],
+               "Atomic": [2,3,4],
+               "Baroque": [2,3,4],
+               "Berolina": [2,4],
+               "Checkered": [2,3,4],
+               "Chess960": [2,3,4],
+               "Crazyhouse": [2,3,4],
+               "Dark": [2,3,4],
+               "Extinction": [2,3,4],
+               "Grand": [2],
+               "Losers": [2,3,4],
+               "Magnetic": [2],
+               "Marseille": [2],
+               "Switching": [2,3,4],
+               "Upsidedown": [2],
+               "Wildebeest": [2],
+               "Zen": [2,3,4],
+       },
+
        getByName: function(name, callback)
        {
                db.serialize(function() {
index 962b8d4..174cf45 100644 (file)
@@ -3,7 +3,6 @@
 let router = require("express").Router();
 const access = require("../utils/access");
 const ChallengeModel = require("../models/Challenge");
-const checkChallenge = require("../data/challengeCheck.js");
 
 router.post("/challenges/:vid([0-9]+)", access.logged, access.ajax, (req,res) => {
        const vid = req.params["vid"];
@@ -16,7 +15,7 @@ router.post("/challenges/:vid([0-9]+)", access.logged, access.ajax, (req,res) =>
                nbPlayers: req.body["nbPlayers"],
                players: req.body["players"],
        };
-       const error = checkChallenge(chall);
+       const error = ChallengeModel.checkChallenge(chall);
        ChallengeModel.create(chall, (err,lastId) => {
                res.json(err || {cid: lastId["rowid"]});
        });
index 2b39cc0..8df0c43 100644 (file)
@@ -6,7 +6,6 @@ var sendEmail = require('../utils/mailer');
 var genToken = require("../utils/tokenGenerator");
 var access = require("../utils/access");
 var params = require("../config/parameters");
-var checkNameEmail = require("../data/userCheck")
 
 // to: object user (to who we send an email)
 function setAndSendLoginToken(subject, to, res)
@@ -33,7 +32,7 @@ router.post('/register', access.unlogged, access.ajax, (req,res) => {
        const name = req.body.name;
        const email = req.body.email;
        const notify = !!req.body.notify;
-       const error = checkNameEmail({name: name, email: email});
+       const error = UserModel.checkNameEmail({name: name, email: email});
        if (!!error)
                return res.json({errmsg: error});
        UserModel.create(name, email, notify, (err,uid) => {
@@ -51,7 +50,7 @@ router.post('/register', access.unlogged, access.ajax, (req,res) => {
 router.get('/sendtoken', access.unlogged, access.ajax, (req,res) => {
        const nameOrEmail = decodeURIComponent(req.query.nameOrEmail);
        const type = (nameOrEmail.indexOf('@') >= 0 ? "email" : "name");
-       const error = checkNameEmail({[type]: nameOrEmail});
+       const error = UserModel.checkNameEmail({[type]: nameOrEmail});
        if (!!error)
                return res.json({errmsg: error});
        UserModel.getOne(type, nameOrEmail, (err,user) => {
@@ -86,7 +85,7 @@ router.get('/authenticate', access.unlogged, (req,res) => {
 router.put('/update', access.logged, access.ajax, (req,res) => {
        const name = req.body.name;
        const email = req.body.email;
-       const error = checkNameEmail({name: name, email: email});
+       const error = UserModel.checkNameEmail({name: name, email: email});
        if (!!error)
                return res.json({errmsg: error});
        const user = {
index 1ebd521..8a0614b 100644 (file)
@@ -2,11 +2,12 @@ const url = require('url');
 const VariantModel = require("./models/Variant");
 
 // Node version in Ubuntu 16.04 does not know about URL class
-function getJsonFromUrl(url) {
-       var query = url.substr(2); //starts with "/?"
-       var result = {};
-       query.split("&").forEach(function(part) {
-               var item = part.split("=");
+function getJsonFromUrl(url)
+{
+       const query = url.substr(2); //starts with "/?"
+       let result = {};
+       query.split("&").forEach((part) => {
+               const item = part.split("=");
                result[item[0]] = decodeURIComponent(item[1]);
        });
        return result;