*.swp
*~
-# Demo video, database
-*.webm
+# Various files
/db/vchess.sqlite
-
-# socket URL file
+/utils/sendEmail.js
/public/javascripts/socket_url.js
# CSS generated files
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")));
}));
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) {
}
},
"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",
},
"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",
},
})
-// 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
Vue.component('my-problems', {
data: function () {
return {
- problems: problemArray, //initial value
+ problems: [],
newProblem: {
fen: "",
instructions: "",
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?!
--- /dev/null
+// 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);
+ }
+ );
+}
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:
+++ /dev/null
-/*
- * 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));
-}
el: "#variantPage",
data: {
display: "room", //default: main hall
+ gameid: "undefined", //...yet
},
created: function() {
// TODO: navigation becomes a little more complex
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)
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
body
padding: 0
min-width: 320px
- margin-bottom: 10px
.container
padding: 0
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
-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;
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+// 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;
+}
--- /dev/null
+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();
+ });
+};
--- /dev/null
+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!"]
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)};
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
-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..."]
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",
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')")
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")
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")