Index page almost OK. Now work on variant page (main hall...)
authorBenjamin Auder <benjamin.auder@somewhere>
Mon, 7 Jan 2019 16:36:27 +0000 (17:36 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Mon, 7 Jan 2019 16:36:27 +0000 (17:36 +0100)
25 files changed:
.gitignore
app.js
package-lock.json
package.json
public/javascripts/components/game.js
public/javascripts/components/problems.js
public/javascripts/contactForm.js [new file with mode: 0644]
public/javascripts/index.js
public/javascripts/utils/md5.js [deleted file]
public/javascripts/variant.js
public/stylesheets/index.sass
public/stylesheets/layout.sass
routes/all.js
routes/index.js [new file with mode: 0644]
routes/messages.js [new file with mode: 0644]
routes/problems.js [new file with mode: 0644]
routes/variant.js [new file with mode: 0644]
utils/language.js [new file with mode: 0644]
utils/sendEmail.js.dist [new file with mode: 0644]
views/contactForm.pug [new file with mode: 0644]
views/index.pug
views/layout.pug
views/settings.pug
views/translations/en.pug
views/variant.pug

index 30651ee..c273cf0 100644 (file)
@@ -15,11 +15,9 @@ pids
 *.swp
 *~
 
-# Demo video, database
-*.webm
+# Various files
 /db/vchess.sqlite
-
-# socket URL file
+/utils/sendEmail.js
 /public/javascripts/socket_url.js
 
 # CSS generated files
diff --git a/app.js b/app.js
index b44be79..914e29b 100644 (file)
--- a/app.js
+++ b/app.js
@@ -6,8 +6,6 @@ var logger = require('morgan');
 var sassMiddleware = require('node-sass-middleware');
 var favicon = require('serve-favicon');
 
-var router = require('./routes/all');
-
 var app = express();
 
 app.use(favicon(path.join(__dirname, "public", "images", "favicon", "favicon.ico")));
@@ -45,7 +43,8 @@ app.use(sassMiddleware({
 }));
 app.use(express.static(path.join(__dirname, 'public')));
 
-app.use('/', router);
+const routes = require(path.join(__dirname, "routes", "all"));
+app.use('/', routes);
 
 // catch 404 and forward to error handler
 app.use(function(req, res, next) {
index cc552a2..2acac2b 100644 (file)
       }
     },
     "debug": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
-      "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
       "requires": {
         "ms": "^2.1.1"
       }
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "core-util-is": {
           "version": "1.0.2",
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "ini": {
           "version": "1.3.5",
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "minipass": {
           "version": "2.2.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.1",
             "yallist": "^3.0.0"
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "object-assign": {
           "version": "4.1.1",
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "wrappy": "1"
           }
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
         "node-sass": "^4.3.0"
       }
     },
+    "nodemailer": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-5.0.0.tgz",
+      "integrity": "sha512-XI4PI5L7GYcJyHkPcHlvPyRrYohNYBNRNbt1tU8PXNU3E1ADJC84a13V0vbL9AM431OP+ETacaGXAF8fGn1JvA=="
+    },
     "nodemon": {
       "version": "1.18.9",
       "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.9.tgz",
index 622ca8f..4a67cf9 100644 (file)
@@ -7,11 +7,12 @@
   },
   "dependencies": {
     "cookie-parser": "~1.4.3",
-    "debug": "~4.1.0",
+    "debug": "^4.1.1",
     "express": "~4.16.4",
     "http-errors": "~1.7.1",
     "morgan": "~1.9.1",
     "node-sass-middleware": "~0.11.0",
+    "nodemailer": "^5.0.0",
     "pug": "~2.0.3",
     "sanitize-html": "^1.20.0",
     "serve-favicon": "~2.5.0",
index fec3df5..c2cce62 100644 (file)
@@ -1480,17 +1480,15 @@ Vue.component('my-game', {
        },
 })
 
-// TODO: keep moves list here
-get lastMove()
-       {
-               const L = this.moves.length;
-               return (L>0 ? this.moves[L-1] : null);
-       }
-
-// here too:
-                       move.notation = this.getNotation(move);
-                       // Hash of current game state *after move*, to detect repetitions
-                       move.hash = hex_md5(this.getBaseFen() + this.getTurnFen() + this.getFlagsFen());
+//// TODO: keep moves list here
+//get lastMove()
+//     {
+//             const L = this.moves.length;
+//             return (L>0 ? this.moves[L-1] : null);
+//     }
+//
+//// here too:
+//                     move.notation = this.getNotation(move);
 //TODO: confirm dialog with "opponent offers draw", avec possible bouton "prevent future offers" + bouton "proposer nulle"
 //+ bouton "abort" avec score == "?" + demander confirmation pour toutes ces actions,
 //comme sur lichess
index 4caabb5..bcd069c 100644 (file)
@@ -1,7 +1,7 @@
 Vue.component('my-problems', {
        data: function () {
                return {
-                       problems: problemArray, //initial value
+                       problems: [],
                        newProblem: {
                                fen: "",
                                instructions: "",
@@ -71,14 +71,18 @@ Vue.component('my-problems', {
                        return this.problems.sort((p1,p2) => { return p2.added - p1.added; });
                },
        },
+       created: function() {
+               // TODO: fetch most recent problems from server
+       },
        methods: {
                translate: function(text) {
                        return translations[text];
                },
-               // Propagate "show problem" event to parent component (my-variant)
-               bubbleUp: function(problem) {
-                       this.$emit('show-problem', JSON.stringify(problem));
-               },
+               // TODO: obsolete:
+//             // Propagate "show problem" event to parent component (my-variant)
+//             bubbleUp: function(problem) {
+//                     this.$emit('show-problem', JSON.stringify(problem));
+//             },
                fetchProblems: function(direction) {
                        if (this.problems.length == 0)
                                return; //what could we do?!
diff --git a/public/javascripts/contactForm.js b/public/javascripts/contactForm.js
new file mode 100644 (file)
index 0000000..0c4fea3
--- /dev/null
@@ -0,0 +1,31 @@
+// 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");
+       if (!email.value.match(/^[^@]+@[^@]+\.[^@]+$/))
+               return alert("Bad email");
+       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);
+               }
+       );
+}
index 6448926..6859e8b 100644 (file)
@@ -49,33 +49,33 @@ new Vue({
                this.conn.onmessage = socketMessageListener;
                this.conn.onclose = socketCloseListener;
        },
-       mounted: function() {
-               // Handle key stroke
-               document.onkeydown = event => {
-                       // Is it Back or Esc? If yes, apply action on current word
-                       if (event.keyCode == 8) //Back
-                       {
-                               event.preventDefault();
-                               this.curPrefix = this.curPrefix.slice(0,-1);
-                       }
-                       else if (event.keyCode == 27) //Esc
-                       {
-                               event.preventDefault();
-                               this.curPrefix = "";
-                       }
-                       // Is it alphanumeric? If yes, stack it
-                       else if (_.range(48,58).includes(event.keyCode)
-                               || _.range(65,91).includes(event.keyCode)
-                               || _.range(97,123).includes(event.keyCode))
-                       {
-                               let newChar = String.fromCharCode(event.keyCode);
-                               this.curPrefix += this.curPrefix.length==0
-                                       ? newChar.toUpperCase()
-                                       : newChar.toLowerCase();
-                       }
-                       // ...ignore everything else
-               };
-       },
+//     mounted: function() {
+//             // Handle key stroke
+//             document.onkeydown = event => {
+//                     // Is it Back or Esc? If yes, apply action on current word
+//                     if (event.keyCode == 8) //Back
+//                     {
+//                             event.preventDefault();
+//                             this.curPrefix = this.curPrefix.slice(0,-1);
+//                     }
+//                     else if (event.keyCode == 27) //Esc
+//                     {
+//                             event.preventDefault();
+//                             this.curPrefix = "";
+//                     }
+//                     // Is it alphanumeric? If yes, stack it
+//                     else if (_.range(48,58).includes(event.keyCode)
+//                             || _.range(65,91).includes(event.keyCode)
+//                             || _.range(97,123).includes(event.keyCode))
+//                     {
+//                             let newChar = String.fromCharCode(event.keyCode);
+//                             this.curPrefix += this.curPrefix.length==0
+//                                     ? newChar.toUpperCase()
+//                                     : newChar.toLowerCase();
+//                     }
+//                     // ...ignore everything else
+//             };
+//     },
 });
 
 // TODO:
diff --git a/public/javascripts/utils/md5.js b/public/javascripts/utils/md5.js
deleted file mode 100644 (file)
index 24d190e..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
- * Digest Algorithm, as defined in RFC 1321.
- * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
- * Distributed under the BSD License
- * See http://pajhome.org.uk/crypt/md5 for more info.
- */
-
-/*
- * Configurable variables. You may need to tweak these to be compatible with
- * the server-side, but the defaults work in most cases.
- */
-var hexcase = 0;   /* hex output format. 0 - lowercase; 1 - uppercase        */
-var b64pad  = "";  /* base-64 pad character. "=" for strict RFC compliance   */
-
-/*
- * These are the functions you'll usually want to call
- * They take string arguments and return either hex or base-64 encoded strings
- */
-function hex_md5(s)    { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
-function b64_md5(s)    { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
-function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
-function hex_hmac_md5(k, d)
-  { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
-function b64_hmac_md5(k, d)
-  { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
-function any_hmac_md5(k, d, e)
-  { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
-
-/*
- * Perform a simple self-test to see if the VM is working
- */
-function md5_vm_test()
-{
-  return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
-}
-
-/*
- * Calculate the MD5 of a raw string
- */
-function rstr_md5(s)
-{
-  return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
-}
-
-/*
- * Calculate the HMAC-MD5, of a key and some data (raw strings)
- */
-function rstr_hmac_md5(key, data)
-{
-  var bkey = rstr2binl(key);
-  if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
-
-  var ipad = Array(16), opad = Array(16);
-  for(var i = 0; i < 16; i++)
-  {
-    ipad[i] = bkey[i] ^ 0x36363636;
-    opad[i] = bkey[i] ^ 0x5C5C5C5C;
-  }
-
-  var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
-  return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
-}
-
-/*
- * Convert a raw string to a hex string
- */
-function rstr2hex(input)
-{
-  try { hexcase } catch(e) { hexcase=0; }
-  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
-  var output = "";
-  var x;
-  for(var i = 0; i < input.length; i++)
-  {
-    x = input.charCodeAt(i);
-    output += hex_tab.charAt((x >>> 4) & 0x0F)
-           +  hex_tab.charAt( x        & 0x0F);
-  }
-  return output;
-}
-
-/*
- * Convert a raw string to a base-64 string
- */
-function rstr2b64(input)
-{
-  try { b64pad } catch(e) { b64pad=''; }
-  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-  var output = "";
-  var len = input.length;
-  for(var i = 0; i < len; i += 3)
-  {
-    var triplet = (input.charCodeAt(i) << 16)
-                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
-                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
-    for(var j = 0; j < 4; j++)
-    {
-      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
-      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
-    }
-  }
-  return output;
-}
-
-/*
- * Convert a raw string to an arbitrary string encoding
- */
-function rstr2any(input, encoding)
-{
-  var divisor = encoding.length;
-  var i, j, q, x, quotient;
-
-  /* Convert to an array of 16-bit big-endian values, forming the dividend */
-  var dividend = Array(Math.ceil(input.length / 2));
-  for(i = 0; i < dividend.length; i++)
-  {
-    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
-  }
-
-  /*
-   * Repeatedly perform a long division. The binary array forms the dividend,
-   * the length of the encoding is the divisor. Once computed, the quotient
-   * forms the dividend for the next step. All remainders are stored for later
-   * use.
-   */
-  var full_length = Math.ceil(input.length * 8 /
-                                    (Math.log(encoding.length) / Math.log(2)));
-  var remainders = Array(full_length);
-  for(j = 0; j < full_length; j++)
-  {
-    quotient = Array();
-    x = 0;
-    for(i = 0; i < dividend.length; i++)
-    {
-      x = (x << 16) + dividend[i];
-      q = Math.floor(x / divisor);
-      x -= q * divisor;
-      if(quotient.length > 0 || q > 0)
-        quotient[quotient.length] = q;
-    }
-    remainders[j] = x;
-    dividend = quotient;
-  }
-
-  /* Convert the remainders to the output string */
-  var output = "";
-  for(i = remainders.length - 1; i >= 0; i--)
-    output += encoding.charAt(remainders[i]);
-
-  return output;
-}
-
-/*
- * Encode a string as utf-8.
- * For efficiency, this assumes the input is valid utf-16.
- */
-function str2rstr_utf8(input)
-{
-  var output = "";
-  var i = -1;
-  var x, y;
-
-  while(++i < input.length)
-  {
-    /* Decode utf-16 surrogate pairs */
-    x = input.charCodeAt(i);
-    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
-    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
-    {
-      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
-      i++;
-    }
-
-    /* Encode output as utf-8 */
-    if(x <= 0x7F)
-      output += String.fromCharCode(x);
-    else if(x <= 0x7FF)
-      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
-                                    0x80 | ( x         & 0x3F));
-    else if(x <= 0xFFFF)
-      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
-                                    0x80 | ((x >>> 6 ) & 0x3F),
-                                    0x80 | ( x         & 0x3F));
-    else if(x <= 0x1FFFFF)
-      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
-                                    0x80 | ((x >>> 12) & 0x3F),
-                                    0x80 | ((x >>> 6 ) & 0x3F),
-                                    0x80 | ( x         & 0x3F));
-  }
-  return output;
-}
-
-/*
- * Encode a string as utf-16
- */
-function str2rstr_utf16le(input)
-{
-  var output = "";
-  for(var i = 0; i < input.length; i++)
-    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
-                                  (input.charCodeAt(i) >>> 8) & 0xFF);
-  return output;
-}
-
-function str2rstr_utf16be(input)
-{
-  var output = "";
-  for(var i = 0; i < input.length; i++)
-    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
-                                   input.charCodeAt(i)        & 0xFF);
-  return output;
-}
-
-/*
- * Convert a raw string to an array of little-endian words
- * Characters >255 have their high-byte silently ignored.
- */
-function rstr2binl(input)
-{
-  var output = Array(input.length >> 2);
-  for(var i = 0; i < output.length; i++)
-    output[i] = 0;
-  for(var i = 0; i < input.length * 8; i += 8)
-    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
-  return output;
-}
-
-/*
- * Convert an array of little-endian words to a string
- */
-function binl2rstr(input)
-{
-  var output = "";
-  for(var i = 0; i < input.length * 32; i += 8)
-    output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
-  return output;
-}
-
-/*
- * Calculate the MD5 of an array of little-endian words, and a bit length.
- */
-function binl_md5(x, len)
-{
-  /* append padding */
-  x[len >> 5] |= 0x80 << ((len) % 32);
-  x[(((len + 64) >>> 9) << 4) + 14] = len;
-
-  var a =  1732584193;
-  var b = -271733879;
-  var c = -1732584194;
-  var d =  271733878;
-
-  for(var i = 0; i < x.length; i += 16)
-  {
-    var olda = a;
-    var oldb = b;
-    var oldc = c;
-    var oldd = d;
-
-    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
-    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
-    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
-    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
-    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
-    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
-    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
-    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
-    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
-    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
-    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
-    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
-    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
-    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
-    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
-    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
-
-    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
-    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
-    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
-    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
-    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
-    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
-    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
-    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
-    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
-    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
-    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
-    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
-    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
-    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
-    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
-    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
-
-    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
-    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
-    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
-    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
-    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
-    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
-    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
-    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
-    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
-    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
-    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
-    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
-    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
-    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
-    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
-    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
-
-    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
-    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
-    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
-    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
-    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
-    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
-    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
-    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
-    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
-    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
-    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
-    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
-    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
-    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
-    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
-    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
-
-    a = safe_add(a, olda);
-    b = safe_add(b, oldb);
-    c = safe_add(c, oldc);
-    d = safe_add(d, oldd);
-  }
-  return Array(a, b, c, d);
-}
-
-/*
- * These functions implement the four basic operations the algorithm uses.
- */
-function md5_cmn(q, a, b, x, s, t)
-{
-  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
-}
-function md5_ff(a, b, c, d, x, s, t)
-{
-  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
-}
-function md5_gg(a, b, c, d, x, s, t)
-{
-  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
-}
-function md5_hh(a, b, c, d, x, s, t)
-{
-  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
-}
-function md5_ii(a, b, c, d, x, s, t)
-{
-  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
-}
-
-/*
- * Add integers, wrapping at 2^32. This uses 16-bit operations internally
- * to work around bugs in some JS interpreters.
- */
-function safe_add(x, y)
-{
-  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
-  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
-  return (msw << 16) | (lsw & 0xFFFF);
-}
-
-/*
- * Bitwise rotate a 32-bit number to the left.
- */
-function bit_rol(num, cnt)
-{
-  return (num << cnt) | (num >>> (32 - cnt));
-}
index ae576d8..736d8b3 100644 (file)
@@ -2,6 +2,7 @@ new Vue({
        el: "#variantPage",
        data: {
                display: "room", //default: main hall
+               gameid: "undefined", //...yet
        },
        created: function() {
                // TODO: navigation becomes a little more complex
index 0d7803f..e38f87d 100644 (file)
@@ -14,7 +14,7 @@
     display: inline-block
     padding: 3px
     border: 1px solid black;
-    margin: 27px 15px 5px 7px
+    margin: 25px 15px 5px 7px
     @media screen and (max-width: 767px)
       margin-top: 7px
 
     font-weight: bold
     padding: 0
     border: none
-    margin-top: 22px
+    margin-top: 21px
     font-size: 1.5em
     @media screen and (max-width: 767px)
       margin-top: 10px
       font-size: 1em
 
-#helpMenu
+#settingsMenu, #introductionMenu
   float: right
   @media screen and (max-width: 767px)
     .info-container
       p
         margin-right: 5px
 
-#flagMenu
-  float: right
-  margin-right: 10px
-  @media screen and (max-width: 767px)
-    margin-right: 5px
-  img
-    display: inline-block
-    height: 30px
-    padding-top: 27px
-    @media screen and (max-width: 767px)
-      padding-top: 8px
-
 // TODO: box-shadow or box-sizing ? https://stackoverflow.com/a/13517809
 .variant
   box-sizing: border-box
     @media screen and (max-width: 767px)
       margin-top: 0
 
-#readThis
-  margin-top: 0
-  color: var(--a-link-color)
-  text-decoration: underline
-
 #welcome
   max-width: 767px
   @media screen and (max-width: 767px)
@@ -92,7 +75,7 @@
       max-width: 552px
   ul
     list-style-type: none
-  // TODO: bad practice, use table to align things...
+  // TODO: bad practice, shouldn't use table to align things...
   table.list-table
     width: 300px
     margin: 0 auto
           padding: 0
           text-align: left
           border: 0
-  #disableMsg
-    color: darkred
index d4f6d6d..dedab08 100644 (file)
@@ -7,7 +7,6 @@ html, *
 body
   padding: 0
   min-width: 320px
-  margin-bottom: 10px
 
 .container
   padding: 0
@@ -34,6 +33,35 @@ body
       border-left: 1px solid var(--button-group-border-color)
       border-top: 0
 
+#settings, #contactForm
+  max-width: 767px
+  @media screen and (max-width: 767px)
+    max-width: 100vw
+
+#emailSent
+  color: blue
+  display: none
+
+footer
+  height: 77px
+  background-color: #000033
+  div
+    line-height: 77px
+    a
+      margin: 0 10px 0 0
+      display: inline-block
+      &:visited, &:link
+        color: white
+    p
+      margin: 0 0 0 10px
+      display: inline-block
+      color: white
+      text-decoration: underline
+  @media screen and (max-width: 767px)
+    height: 43px
+    div
+      line-height: 43px
+
 a
   text-decoration: underline
 
index 79f7c3d..7c2a6da 100644 (file)
@@ -1,138 +1,8 @@
-let express = require('express');
-let router = express.Router();
-const createError = require('http-errors');
-const sqlite3 = require('sqlite3');//.verbose();
-const DbPath = __dirname.replace("/routes", "/db/vchess.sqlite");
-const db = new sqlite3.Database(DbPath);
-const sanitizeHtml = require('sanitize-html');
-const MaxNbProblems = 20;
+var router = require("express").Router();
 
-const supportedLang = ["en","es","fr"];
-function selectLanguage(req, res)
-{
-       // If preferred language already set:
-       if (!!req.cookies["lang"])
-               return req.cookies["lang"];
-
-       // Else: search and set it
-       const langString = req.headers["accept-language"];
-       let langArray = langString
-               .replace(/;q=[0-9.]+/g, "") //priority
-               .replace(/-[A-Z]+/g, "") //region (skipped for now...)
-               .split(",") //may have some duplicates, but removal is too costly
-       let bestLang = "en"; //default: English
-       for (let lang of langArray)
-       {
-               if (supportedLang.includes(lang))
-               {
-                       bestLang = lang;
-                       break;
-               }
-       }
-       // Cookie expires in 183 days (expressed in milliseconds)
-       res.cookie('lang', bestLang, { maxAge: 183*24*3600*1000 });
-       return bestLang;
-}
-
-// Home
-router.get('/', function(req, res, next) {
-       db.serialize(function() {
-               db.all("SELECT * FROM Variants", (err,variants) => {
-                       if (!!err)
-                               return next(err);
-                       res.render('index', {
-                               title: 'club',
-                               variantArray: variants,
-                               lang: selectLanguage(req, res),
-                               languages: supportedLang,
-                       });
-               });
-       });
-});
-
-// Variant
-router.get("/:variant([a-zA-Z0-9]+)", (req,res,next) => {
-       const vname = req.params["variant"];
-       db.serialize(function() {
-               db.all("SELECT * FROM Variants WHERE name='" + vname + "'", (err,variant) => {
-                       if (!!err)
-                               return next(err);
-                       if (!variant || variant.length==0)
-                               return next(createError(404));
-                       // Get only N most recent problems
-                       const query2 = "SELECT * FROM Problems " +
-                               "WHERE variant='" + vname + "' " +
-                               "ORDER BY added DESC " +
-                               "LIMIT " + MaxNbProblems;
-                       db.all(query2, (err2,problems) => {
-                               if (!!err2)
-                                       return next(err2);
-                               res.render('variant', {
-                                       title: vname + ' Variant',
-                                       variant: vname,
-                                       problemArray: problems,
-                                       lang: selectLanguage(req, res),
-                                       languages: supportedLang,
-                               });
-                       });
-               });
-       });
-});
-
-// Load a rules page (AJAX)
-router.get("/rules/:variant([a-zA-Z0-9]+)", (req,res) => {
-       if (!req.xhr)
-               return res.json({errmsg: "Unauthorized access"});
-       const lang = selectLanguage(req, res);
-       res.render("rules/" + req.params["variant"] + "/" + lang);
-});
-
-// Fetch N previous or next problems (AJAX)
-router.get("/problems/:variant([a-zA-Z0-9]+)", (req,res) => {
-       if (!req.xhr)
-               return res.json({errmsg: "Unauthorized access"});
-       const vname = req.params["variant"];
-       const directionStr = (req.query.direction == "forward" ? ">" : "<");
-       const lastDt = req.query.last_dt;
-       if (!lastDt.match(/[0-9]+/))
-               return res.json({errmsg: "Bad timestamp"});
-       db.serialize(function() {
-               const query = "SELECT * FROM Problems " +
-                       "WHERE variant='" + vname + "' " +
-                       "  AND added " + directionStr + " " + lastDt + " " +
-                       "ORDER BY added " + (directionStr=="<" ? "DESC " : "") +
-                       "LIMIT " + MaxNbProblems;
-               db.all(query, (err,problems) => {
-                       if (!!err)
-                               return res.json(err);
-                       return res.json({problems: problems});
-               });
-       });
-});
-
-// Upload a problem (AJAX)
-router.post("/problems/:variant([a-zA-Z0-9]+)", (req,res) => {
-       if (!req.xhr)
-               return res.json({errmsg: "Unauthorized access"});
-       const vname = req.params["variant"];
-       const timestamp = Date.now();
-       // Sanitize them
-       const fen = req.body["fen"];
-       if (!fen.match(/^[a-zA-Z0-9, /-]*$/))
-               return res.json({errmsg: "Bad characters in FEN string"});
-       const instructions = sanitizeHtml(req.body["instructions"]).trim();
-       const solution = sanitizeHtml(req.body["solution"]).trim();
-       if (instructions.length == 0)
-               return res.json({errmsg: "Empty instructions"});
-       if (solution.length == 0)
-               return res.json({errmsg: "Empty solution"});
-       db.serialize(function() {
-               let stmt = db.prepare("INSERT INTO Problems " +
-                       "(added,variant,fen,instructions,solution) VALUES (?,?,?,?,?)");
-               stmt.run(timestamp, vname, fen, instructions, solution);
-               stmt.finalize();
-       });
-  res.json({});
-});
+router.use("/", require("./index"));
+router.use("/", require("./variant"));
+router.use("/", require("./problems"));
+router.use("/", require("./messages"));
 
 module.exports = router;
diff --git a/routes/index.js b/routes/index.js
new file mode 100644 (file)
index 0000000..ab44cf5
--- /dev/null
@@ -0,0 +1,21 @@
+let router = require("express").Router();
+const sqlite3 = require('sqlite3');//.verbose();
+const DbPath = __dirname.replace("/routes", "/db/vchess.sqlite");
+const db = new sqlite3.Database(DbPath);
+const selectLanguage = require(__dirname.replace("/routes", "/utils/language.js"));
+
+router.get('/', function(req, res, next) {
+       db.serialize(function() {
+               db.all("SELECT * FROM Variants", (err,variants) => {
+                       if (!!err)
+                               return next(err);
+                       res.render('index', {
+                               title: 'club',
+                               variantArray: variants,
+                               lang: selectLanguage(req, res),
+                       });
+               });
+       });
+});
+
+module.exports = router;
diff --git a/routes/messages.js b/routes/messages.js
new file mode 100644 (file)
index 0000000..7e60b7c
--- /dev/null
@@ -0,0 +1,20 @@
+let router = require("express").Router();
+const sendEmail = require(__dirname.replace("/routes", "/utils/sendEmail"));
+
+// Send a message through contact form
+router.post("/messages", (req,res,next) => {
+       if (!req.xhr)
+               return res.json({errmsg: "Unauthorized access"});
+       const email = req.body["email"];
+       const subject = req.body["subject"];
+       const content = req.body["content"];
+       // TODO: sanitize ?
+       sendEmail(email, subject, content, err => {
+               if (!!err)
+                       return res.json({errmsg:err});
+               // OK, everything fine
+               res.json({}); //ignored
+       });
+});
+
+module.exports = router;
diff --git a/routes/problems.js b/routes/problems.js
new file mode 100644 (file)
index 0000000..62a2da1
--- /dev/null
@@ -0,0 +1,58 @@
+let router = require("express").Router();
+const sqlite3 = require('sqlite3');
+const DbPath = __dirname.replace("/routes", "/db/vchess.sqlite");
+const db = new sqlite3.Database(DbPath);
+const sanitizeHtml = require('sanitize-html');
+const MaxNbProblems = 20;
+
+// Fetch N previous or next problems (AJAX)
+router.get("/problems/:variant([a-zA-Z0-9]+)", (req,res) => {
+       if (!req.xhr)
+               return res.json({errmsg: "Unauthorized access"});
+       const vname = req.params["variant"];
+       const directionStr = (req.query.direction == "forward" ? ">" : "<");
+       const lastDt = req.query.last_dt;
+       if (!lastDt.match(/[0-9]+/))
+               return res.json({errmsg: "Bad timestamp"});
+       db.serialize(function() {
+               const query = "SELECT * FROM Problems " +
+                       "WHERE variant='" + vname + "' " +
+                       "  AND added " + directionStr + " " + lastDt + " " +
+                       "ORDER BY added " + (directionStr=="<" ? "DESC " : "") +
+                       "LIMIT " + MaxNbProblems;
+               db.all(query, (err,problems) => {
+                       if (!!err)
+                               return res.json(err);
+                       return res.json({problems: problems});
+               });
+       });
+});
+
+// Upload a problem (AJAX)
+router.post("/problems/:variant([a-zA-Z0-9]+)", (req,res) => {
+       if (!req.xhr)
+               return res.json({errmsg: "Unauthorized access"});
+       const vname = req.params["variant"];
+       const timestamp = Date.now();
+       // Sanitize them
+       const fen = req.body["fen"];
+       if (!fen.match(/^[a-zA-Z0-9, /-]*$/))
+               return res.json({errmsg: "Bad characters in FEN string"});
+       const instructions = sanitizeHtml(req.body["instructions"]).trim();
+       const solution = sanitizeHtml(req.body["solution"]).trim();
+       if (instructions.length == 0)
+               return res.json({errmsg: "Empty instructions"});
+       if (solution.length == 0)
+               return res.json({errmsg: "Empty solution"});
+       db.serialize(function() {
+               let stmt = db.prepare("INSERT INTO Problems " +
+                       "(added,variant,fen,instructions,solution) VALUES (?,?,?,?,?)");
+               stmt.run(timestamp, vname, fen, instructions, solution);
+               stmt.finalize();
+       });
+  res.json({});
+});
+
+// TODO: edit, delete a problem
+
+module.exports = router;
diff --git a/routes/variant.js b/routes/variant.js
new file mode 100644 (file)
index 0000000..44b7d80
--- /dev/null
@@ -0,0 +1,33 @@
+let router = require("express").Router();
+const createError = require('http-errors');
+const sqlite3 = require('sqlite3');
+const DbPath = __dirname.replace("/routes", "/db/vchess.sqlite");
+const db = new sqlite3.Database(DbPath);
+const selectLanguage = require(__dirname.replace("/routes", "/utils/language.js"));
+
+router.get("/:variant([a-zA-Z0-9]+)", (req,res,next) => {
+       const vname = req.params["variant"];
+       db.serialize(function() {
+               db.all("SELECT * FROM Variants WHERE name='" + vname + "'", (err,variant) => {
+                       if (!!err)
+                               return next(err);
+                       if (!variant || variant.length==0)
+                               return next(createError(404));
+                       res.render('variant', {
+                               title: vname + ' Variant',
+                               variant: vname,
+                               lang: selectLanguage(req, res),
+                       });
+               });
+       });
+});
+
+// Load a rules page (AJAX)
+router.get("/rules/:variant([a-zA-Z0-9]+)", (req,res) => {
+       if (!req.xhr)
+               return res.json({errmsg: "Unauthorized access"});
+       const lang = selectLanguage(req, res);
+       res.render("rules/" + req.params["variant"] + "/" + lang);
+});
+
+module.exports = router;
diff --git a/utils/language.js b/utils/language.js
new file mode 100644 (file)
index 0000000..52c3842
--- /dev/null
@@ -0,0 +1,27 @@
+// Select a language based on browser preferences, or cookie
+module.exports = function(req, res)
+{
+       // If preferred language already set:
+       if (!!req.cookies["lang"])
+               return req.cookies["lang"];
+
+       // Else: search and set it
+       const supportedLang = ["en","es","fr"];
+       const langString = req.headers["accept-language"];
+       let langArray = langString
+               .replace(/;q=[0-9.]+/g, "") //priority
+               .replace(/-[A-Z]+/g, "") //region (skipped for now...)
+               .split(",") //may have some duplicates, but removal is too costly
+       let bestLang = "en"; //default: English
+       for (let lang of langArray)
+       {
+               if (supportedLang.includes(lang))
+               {
+                       bestLang = lang;
+                       break;
+               }
+       }
+       // Cookie expires in 183 days (expressed in milliseconds)
+       res.cookie('lang', bestLang, { maxAge: 183*24*3600*1000 });
+       return bestLang;
+}
diff --git a/utils/sendEmail.js.dist b/utils/sendEmail.js.dist
new file mode 100644 (file)
index 0000000..cad123e
--- /dev/null
@@ -0,0 +1,32 @@
+const nodemailer = require('nodemailer');
+
+module.exports = function(email, subject, content, cb)
+{
+  // create reusable transporter object using the default SMTP transport
+       const transporter = nodemailer.createTransport({
+               host: "smtp_host_address",
+               port: 465, //if secure; otherwise use 587
+               secure: true,
+               auth: {
+                       user: "user_name",
+                       pass: "user_password"
+               }
+       });
+
+       // setup email data with unicode symbols
+       const mailOptions = {
+               from: email, //note: some SMTP serves might forbid this
+               to: "contact_email",
+               subject: subject,
+               text: content,
+  };
+
+       // send mail with defined transport object
+       transporter.sendMail(mailOptions, (error, info) => {
+               if (!!error)
+                       return cb(error);
+    // Ignore info. Option:
+               //console.log('Message sent: %s', info.messageId);
+               return cb();
+  });
+};
diff --git a/views/contactForm.pug b/views/contactForm.pug
new file mode 100644 (file)
index 0000000..a07369e
--- /dev/null
@@ -0,0 +1,18 @@
+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!"]
index 5d27eb8..dd09593 100644 (file)
@@ -14,21 +14,23 @@ block content
                                include welcome/fr
                .row
                        #header.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-                               #mainTitle.clickable(
-                                               onClick="document.getElementById('modalWelcome').checked=true")
+                               #mainTitle
                                        img(src="/images/index/unicorn.svg")
                                        .info-container
                                                p vchess.club
                                        img(src="/images/index/wildebeest.svg")
-                               #settings.clickable(
+                               #settingsMenu.clickable(
                                                onClick="document.getElementById('modalSettings').checked=true")
-                                       i.material-icons settings
+                                       .info-container
+                                               p Settings
+                               #introductionMenu.clickable(
+                                               onClick="document.getElementById('modalWelcome').checked=true")
+                                       .info-container
+                                               p Introduction
                .row
                        my-variant-summary(v-for="(v,idx) in sortedCounts"
                                v-bind:vobj="v" v-bind:index="idx" v-bind:key="v.name")
 
-                                       redesign index page :: lien github, lien contact mail, settings
-
 block javascripts
        script.
                const variantArray = !{JSON.stringify(variantArray)};
index d894ff0..da99fc3 100644 (file)
@@ -25,20 +25,29 @@ html
 
        body
 
+               include langNames
+               case lang
+                       when "en"
+                               include translations/en
+                       when "es"
+                               include translations/es
+                       when "fr"
+                               include translations/fr
+               include contactForm
+               include settings
                main
-                       include langNames
-                       case lang
-                               when "en"
-                                       include translations/en
-                               when "es"
-                                       include translations/es
-                               when "fr"
-                                       include translations/fr
-                       include settings
                        block content
+               footer.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2.text-center
+                       div
+                               a(href="https://github.com/yagu0/vchess") Source code
+                               p.clickable(onClick="document.getElementById('modalContact').checked=true")
+                                       =translations["Contact"]
 
                script(src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js")
+               script(src="/javascripts/utils/ajax.js")
                script(src="/javascripts/layout.js")
+               script(src="/javascripts/settings.js")
+               script(src="/javascripts/contactForm.js")
                if development
                        script(src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js")
                else
index c46c5f8..063e61a 100644 (file)
@@ -1,15 +1,15 @@
-input#modal-settings.modal(type="checkbox")
+input#modalSettings.modal(type="checkbox")
 div(role="dialog" aria-labelledby="settingsTitle")
        .card.smallpad(onChange="blabla(event)")
-               label#close-settings.modal-close(for="modal-settings")
+               label.modal-close(for="modalSettings")
                h3#settingsTitle.section= translations["Preferences"]
                fieldset
                        label(for="langSelect")= translations["Language"]
                        // image avec drapeau + select language ici
                        select#langSelect
-                               each langCode in languages
+                               each language,langCode in langName
                                        option(value=langCode selected=(lang==langCode))
-                                               =langName[langCode]
+                                               =language
                fieldset
                        label(for="nameSetter")
                                =translations["My name is..."]
index fe67aba..9663311 100644 (file)
@@ -2,6 +2,13 @@
        var translations =
        {
                "Language": "Language",
+               "Contact": "Contact",
+               "Email": "Email",
+               "Subject": "Subject",
+               "Content": "Content",
+               "Email sent!": "Email sent!",
+               "Hall": "Hall",
+               "My games": "My games",
 
                // Index page:
                "Help": "Help",
index ca9091b..a43ba60 100644 (file)
@@ -16,7 +16,7 @@ block content
                                        a(href="#room" @click="setDisplay('room')")
                                                =translations["Hall"]
                                        a(href="#gameList" @click="setDisplay('gameList')")
-                                               =translations["Play"]
+                                               =translations["My games"]
                                        a(href="#rules" @click="setDisplay('rules')")
                                                =translations["Rules"]
                                        a(href="#problems" @click="setDisplay('problems')")
@@ -30,14 +30,12 @@ block content
                        my-rules(v-show="display=='rules'")
                        my-problems(v-show="display=='problems'")
                        // my-game: for room and games-list components
-                       my-game(v-show="display=='game'" :gameId="")
+                       my-game(v-show="display=='game'" :gameId="gameid")
 
 block javascripts
        script(src="/javascripts/utils/misc.js")
        script(src="/javascripts/utils/array.js")
-       script(src="/javascripts/utils/md5.js")
        script(src="/javascripts/utils/printDiagram.js")
-       script(src="/javascripts/utils/ajax.js")
        script(src="/javascripts/utils/datetime.js")
        script(src="/javascripts/socket_url.js")
        script(src="/javascripts/base_rules.js")
@@ -45,7 +43,6 @@ block javascripts
        script.
                const V = VariantRules; //because this variable is often used
                const variant = "#{variant}";
-               const problemArray = !{JSON.stringify(problemArray)};
        script(src="/javascripts/components/rules.js")
        script(src="/javascripts/components/game.js")
        script(src="/javascripts/components/problemSummary.js")