From 94312a9862f256d15d623659af3979f4310ac6d1 Mon Sep 17 00:00:00 2001 From: Klemek Date: Thu, 14 Oct 2021 14:43:00 +0200 Subject: [PATCH] initial commit --- .eslintignore | 1 + .eslintrc.js | 102 +++++++++++++++++++ .jshintignore | 1 - .jshintrc | 26 ----- index.html | 43 +++++--- main.js | 266 ++++++++++++++++++++++++++++++++++---------------- style.css | 98 ++++++++++++++----- 7 files changed, 389 insertions(+), 148 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.js delete mode 100644 .jshintignore delete mode 100644 .jshintrc diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..dc55552 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +/lib \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..c858ce0 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,102 @@ +module.exports = { + env: { + 'commonjs': true, + 'es2021': true, + }, + extends: [ + 'eslint:recommended', + ], + parserOptions: { + ecmaVersion: 12, + }, + rules: { + 'indent': [ + 'error', + 4, + ], + 'linebreak-style': [ + 'error', + 'unix', + ], + 'quotes': [ + 'error', + 'single', + ], + 'semi': [ + 'error', + 'always', + ], + 'curly': [ + 'error', + 'all', + ], + 'brace-style': [ + 'error', + '1tbs', + ], + 'jest/no-done-callback': 'off', + 'jest/expect-expect': 'off', + 'comma-dangle': [ + 'error', + 'always-multiline', + ], + 'complexity': 'error', + 'consistent-return': 'error', + 'dot-location': [ + 'error', + 'property', + ], + 'eqeqeq': [ + 'error', + 'always', + { null: 'ignore' }, + ], + 'no-empty-function': 'error', + 'no-floating-decimal': 'error', + 'no-multi-spaces': 'error', + 'camelcase': [ + 'error', + { properties: 'never' }, + ], + 'comma-spacing': [ + 'error', + { before: false, after: true }, + ], + 'array-bracket-newline': [ + 'error', + { multiline: true }, + ], + 'array-element-newline': [ + 'error', + { multiline: true, minItems: 2 }, + ], + 'array-bracket-spacing': [ + 'error', + 'always', + ], + 'object-curly-spacing': [ + 'error', + 'always', + ], + 'comma-style': 'error', + 'computed-property-spacing': 'error', + 'eol-last': 'error', + 'func-call-spacing': 'error', + 'key-spacing': 'error', + 'keyword-spacing': 'error', + 'multiline-comment-style': 'error', + 'newline-per-chained-call': 'error', + 'no-lonely-if': 'error', + 'no-multiple-empty-lines': 'error', + 'no-trailing-spaces': 'error', + 'no-unneeded-ternary': 'error', + 'no-whitespace-before-property': 'error', + 'operator-assignment': 'error', + 'quote-props': [ + 'error', + 'consistent-as-needed', + ], + 'space-before-blocks': 'error', + 'space-infix-ops': 'error', + }, +}; \ No newline at end of file diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 7951405..0000000 --- a/.jshintignore +++ /dev/null @@ -1 +0,0 @@ -lib \ No newline at end of file diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 136f436..0000000 --- a/.jshintrc +++ /dev/null @@ -1,26 +0,0 @@ -{ - "esversion": 6, - "maxerr": 999, - "indent": true, - "camelcase": true, - "eqeqeq": true, - "forin": true, - "immed": true, - "latedef": true, - "noarg": true, - "noempty": true, - "nonew": true, - "undef": true, - "unused": true, - "varstmt": true, - "sub": true, - "quotmark": "single", - "browser": true, - "devel": true, - "globals": { - "Vue": false, - "data": true, - "cookies": true, - "app": true - } -} \ No newline at end of file diff --git a/index.html b/index.html index 32dbb7a..d032e21 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,12 @@ - - - Change this you moron - + + + Kana Test + - + - - -
-

{{title}}

-
-

-
- @Klemek - Github Repository - 2019 + + +
+

{{title}}

+
score : {{ score }}
+
{{question}}
+
+
{{ v }}
+
+

Options

+
+
+
+
+ + + +
+
+ @Klemek - + Github Repository - 2021
- + diff --git a/main.js b/main.js index 18168bd..6621a64 100644 --- a/main.js +++ b/main.js @@ -1,99 +1,199 @@ /* exported app, utils */ -const utils = { - ajax: { - proxy: 'cors-anywhere.herokuapp.com', - /** - * Define a get HTTP request to be executed with .then/.catch - * @param {string} url - * @param {Object} data - * @param {boolean} proxy - use cors proxy - * @returns {Promise} return JSON parsed data or string - */ - get: (url, data, proxy = false) => { - return new Promise((resolve, reject) => { - if (data && Object.keys(data).length) { - url += '?' + Object.keys(data) - .map(k => k + '=' + encodeURIComponent(data[k])) - .join('&') - .replace(/%20/g, '+'); - } - const xhr = new XMLHttpRequest(); - if (proxy) { - const http = (window.location.protocol === 'http:' ? 'http:' : 'https:'); - url = `${http}//${utils.ajax.proxy}/${url}`; - } - xhr.open('GET', url); - xhr.onload = () => { - try { - resolve(JSON.parse(xhr.responseText)); - } catch (ignored) { - resolve(xhr.responseText); - } - }; - xhr.onerror = () => reject(xhr); - xhr.send(); - }); - }, +const kanas = { + columns: ["A", "I", "U", "E", "O"], + rows: ["", "K", "S", "T", "N", "H", "M", "Y", "R", "W", "(N)"], + hiraganas: [ + ["あ", "い", "う", "え", "お"], + ["か", "き", "く", "け", "こ"], + ["さ", "し", "す", "せ", "そ"], + ["た", "ち", "つ", "て", "と"], + ["な", "に", "ぬ", "ね", "の"], + ["は", "ひ", "ふ", "へ", "ほ"], + ["ま", "み", "む", "め", "も"], + ["や", "", "ゆ", "", "よ"], + ["ら", "り", "る", "れ", "ろ"], + ["わ", "", "", "", "を"], + ["ん"], + ], + katakanas: [ + ["ア", "イ", "ウ", "エ", "オ"], + ["カ", "キ", "ク", "ケ", "コ"], + ["サ", "シ", "ス", "セ", "ソ"], + ["タ", "チ", "ツ", "テ", "ト"], + ["ナ", "ニ", "ヌ", "ネ", "ノ"], + ["ハ", "ヒ", "フ", "ヘ", "ホ"], + ["マ", "ミ", "ム", "メ", "モ"], + ["ヤ", "", "ユ", "", "ヨ"], + ["ラ", "リ", "ル", "レ", "ロ"], + ["ワ", "", "", "", "ヲ"], + ["ン"], + ], + exceptions: { + SI: "SHI", + TI: "CHI", + TU: "TSU", + HU: "FU", }, - cookies: { - /** - * Save a value in a cookie - * @param {string} name - * @param {string} value - * @param {number | undefined} days - */ - set: function (name, value, days = undefined) { - const maxAge = !days ? undefined : days * 864e2; - document.cookie = `${name}=${encodeURIComponent(value)}${maxAge ? `;max-age=${maxAge};` : ''}`; - }, - /** - * Get a value from a cookie - * @param {string} name - * @return {string} value from cookie or empty if not found - */ - get: function (name) { - return document.cookie.split('; ').reduce(function (r, v) { - const parts = v.split('='); - return parts[0] === name ? decodeURIComponent(parts[1]) : r; - }, ''); - }, - /** - * Delete a cookie - * @param {string} name - */ - delete: function (name) { - this.set(name, '', -1); - }, - /** - * Clear all cookies - */ - clear: function () { - const cookies = document.cookie.split(';'); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i]; - const eqPos = cookie.indexOf('='); - const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; - document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`; - } +}; + +const utils = { + randint: function (min, max) { + return Math.floor(Math.random() * (max - min)) + min; + }, + randindex: function (array, ...toIgnore) { + let index; + do { + index = this.randint(0, array.length); + } while (this.contains(toIgnore, index)); + return index; + }, + randitem: function (array) { + return array[this.randindex(array)]; + }, + randindexes: function (array, number, ...toIgnore) { + const output = []; + for (let i = 0; i < number; i++) { + output.push(this.randindex(array, ...output, ...toIgnore)); } + return output; + }, + shuffle: function (array) { + const output = [...array]; + for (let i = 0; i < array.length; i++) { + const i1 = this.randindex(array); + const i2 = this.randindex(array, i1); + [output[i1], output[i2]] = [output[i2], output[i1]]; + } + return output; + }, + contains: function(array, item) { + return array.indexOf(item) >= 0; } }; +Array.prototype.shuffle = function() { return utils.shuffle(this);}; +Array.prototype.contains = function(item) { return utils.contains(this, item);}; + let app = { - el: '#app', + el: "#app", data: { - title: 'Vue-Boilerplate', - content: 'Fill this page with whatever you\'re going to develop.
Then enjoy!' + title: "Kana Test", + score: 0, + options: { + available: kanas.rows, + selected: kanas.rows, + rh: true, + rk: false, + hk: false, + answers: 4, + }, + kanas: [], + question: "あ", + answers: ["A", "I", "U", "O"], + wrongAnswers: [], }, - methods: {}, - 'mounted': function () { + watch: { + options: { + handler: "changeOption", + deep: true, + }, + }, + methods: { + buildKanas: function () { + const self = this; + self.kanas = []; + self.options.selected.forEach((prefix) => { + const row = kanas.rows.indexOf(prefix); + if (prefix === "(N)") { + self.kanas.push([ + "N", + kanas.hiraganas[row][0], + kanas.katakanas[row][0], + ]); + } else { + kanas.columns.forEach((suffix, column) => { + const text = kanas.exceptions[prefix + suffix] + ? kanas.exceptions[prefix + suffix] + : prefix + suffix; + if (kanas.hiraganas[row][column] || kanas.katakanas[row][column]) { + self.kanas.push([ + text, + kanas.hiraganas[row][column], + kanas.katakanas[row][column], + ]); + } + }); + } + }); + }, + generateQuestion: function () { + const self = this; + const questionIndex = utils.randindex(self.kanas); + const answerIndexes = utils.randindexes( + self.kanas, + self.options.answers - 1, + questionIndex + ); + //TODO add difficulty + + const mappings = []; + if (self.options.rh) { + mappings.push([0, 1], [1, 0]); + } + if (self.options.rk) { + mappings.push([0, 2], [2, 0]); + } + if (self.options.hk) { + mappings.push([1, 2], [2, 1]); + } + const mapping = utils.randitem(mappings); + + self.question = self.kanas[questionIndex][mapping[0]]; + self.answers = [questionIndex] + .concat(answerIndexes) + .map((index) => self.kanas[index][mapping[1]]); + self.answers = self.answers.shuffle(); + self.wrongAnswers = []; + }, + answer: function (v) { + const self = this; + + const question = self.kanas.filter(kana => { + return kana.contains(self.question); + })[0]; + + if(question.contains(v)) { + self.score += 1; + self.generateQuestion(); + } else { + self.score = 0; + self.wrongAnswers.push(v); + } + + }, + changeOption: function (v) { + const self = this; + if (!self.options.rh && !self.options.rk && !self.options.hk) { + self.options.rh = true; + } + if (self.options.selected.length === 0) { + self.options.selected.push(""); + } + self.score = 0; + self.buildKanas(); + self.generateQuestion(); + }, + }, + mounted: function () { const self = this; - console.log('app mounted'); + console.log("app mounted"); setTimeout(() => { - self.$el.setAttribute('style', ''); + self.$el.setAttribute("style", ""); }); - } + self.buildKanas(); + self.generateQuestion(); + }, }; window.onload = () => { diff --git a/style.css b/style.css index 85ce010..4925125 100644 --- a/style.css +++ b/style.css @@ -1,42 +1,92 @@ * { - box-sizing: border-box; - font-family: Verdana, serif; - color: #424242; + box-sizing: border-box; + font-family: Verdana, serif; + color: #424242; } -html, body { - margin: 0; - padding: 0; - height: 100vh; - max-width: 100%; +html, +body { + margin: 0; + padding: 0; + height: 100vh; + max-width: 100%; } body { - background-color: #F5F5F5; + background-color: #f5f5f5; } main { - padding: 1.5rem; - margin: auto; - background-color: #EEEEEE; - min-height: 100%; + padding: 1.5rem; + margin: auto; + background-color: #eeeeee; + min-height: 100%; } h1 { - margin-bottom: .5em; + margin-bottom: 0.5em; } -table{ - border-collapse: collapse; - width:100%; - font-size: .9em; +table { + border-collapse: collapse; + width: 100%; + font-size: 0.9em; } @media only screen and (min-width: 768px) { - main { - max-width: 42rem; - } - table{ - font-size:inherit; - } + main { + max-width: 42rem; + } + table { + font-size: inherit; + } +} + +#score { + text-align: center; +} + +#question { + text-align: center; + font-size: 4em; +} + +#question > span { + line-height: 1.5em; +} + +#answers { + text-align: center; +} + +.answer { + font-size: 1.5em; + width: 3.5em; + height: 2em; + text-align: center; + padding: 0; + margin: 0.2em; + border: 1px solid #424242; + border-radius: .1em; + display:inline-block; + line-height: 2em; + cursor: pointer; + background-color: #FAFAFA; + color: #424242; +} + +.answer:hover { + background-color: #E0E0E0; + color: #424242; +} + +.answer:active { + background-color: #757575; + color: #eeeeee; +} + +.disabled { + background-color: #f44336; + color: #eeeeee; + cursor: default; }