diff options
Diffstat (limited to 'resources')
-rw-r--r-- | resources/audio/negative.wav | bin | 0 -> 216736 bytes | |||
-rw-r--r-- | resources/audio/positive.wav | bin | 0 -> 151198 bytes | |||
-rw-r--r-- | resources/css/fonts/SBL_grk.ttf | bin | 0 -> 1123080 bytes | |||
-rw-r--r-- | resources/css/luoparsetrainer.css | 81 | ||||
-rw-r--r-- | resources/js/app.js | 3 | ||||
-rw-r--r-- | resources/js/luoparsetrainer.js | 435 | ||||
-rw-r--r-- | resources/views/layouts/master.blade.php | 8 |
7 files changed, 522 insertions, 5 deletions
diff --git a/resources/audio/negative.wav b/resources/audio/negative.wav Binary files differnew file mode 100644 index 0000000..8718ca9 --- /dev/null +++ b/resources/audio/negative.wav diff --git a/resources/audio/positive.wav b/resources/audio/positive.wav Binary files differnew file mode 100644 index 0000000..ea09f84 --- /dev/null +++ b/resources/audio/positive.wav diff --git a/resources/css/fonts/SBL_grk.ttf b/resources/css/fonts/SBL_grk.ttf Binary files differnew file mode 100644 index 0000000..90a807b --- /dev/null +++ b/resources/css/fonts/SBL_grk.ttf diff --git a/resources/css/luoparsetrainer.css b/resources/css/luoparsetrainer.css new file mode 100644 index 0000000..9b72da1 --- /dev/null +++ b/resources/css/luoparsetrainer.css @@ -0,0 +1,81 @@ +/** + * Luo Parse Trainer - practice Ancient Greek verb forms + * Copyright (C) 2015-present Camil Staps <info@camilstaps.nl> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +@font-face { + font-family: 'SBL Greek'; + src: url('fonts/SBL_grk.ttf'); +} + +body { + font-family: 'SBL Greek', 'Palatino Linotype'; + padding-top: 20px; +} + +.large { + font-size: 150%; +} + +.header { + border-bottom: 1px solid #e5e5e5; + margin-bottom: 30px; +} + +.header h2 a { + color: inherit !important; + text-decoration: none !important; +} + +.suggestions td { + vertical-align: middle !important; +} + +.suggestions td.vote-cell { + width: 30px; +} + +#trainer { + margin-bottom: 70px; +} + +#trainer-404 { + display: none; + padding: 15px; +} + +#trainer-input-fancy { + display: inline-block; + margin-bottom: 20px; +} + +#trainer-input-fancy button { + margin-bottom: 3px; + min-width: 7em; + width: 100%; +} + +#trainer-input-fancy button.ptc { + margin-right: 3px; + width: 30%; +} + +#trainer-input-help { + display: none; +} + +.greek-large { + font-size: 40px; +} diff --git a/resources/js/app.js b/resources/js/app.js new file mode 100644 index 0000000..d5377db --- /dev/null +++ b/resources/js/app.js @@ -0,0 +1,3 @@ +window.$ = window.jQuery = require('jquery'); +require('bootstrap'); +require('./luoparsetrainer'); diff --git a/resources/js/luoparsetrainer.js b/resources/js/luoparsetrainer.js new file mode 100644 index 0000000..45965d8 --- /dev/null +++ b/resources/js/luoparsetrainer.js @@ -0,0 +1,435 @@ +/** + * Luo Parse Trainer - practice Ancient Greek verb forms + * Copyright (C) 2015-present Camil Staps <info@camilstaps.nl> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +$(document).ready(function(){ + var audio_positive = new Audio('public/audio/positive.wav'); + var audio_negative = new Audio('public/audio/negative.wav'); + + var correct_answers; + var input_count = 0; + var checked = false; + + function stepFancyInput(step, val) { + $('#trainer-input-fancy').html(''); + var buts = {}; + switch (step) { + case 0: + buts = { 'pr ': 'Praesens' + , 'impf ': 'Imperfectum' + , 'aor ': 'Aoristus' + , 'fut ': 'Futurum' + , 'pf ': 'Perfectum' + , 'pqpf ': 'Plusquamperfectum' + }; break; + case 1: + buts = { 'ind ': 'Indicativus' + , 'conj ': 'Conjunctivus' + , 'opt ': 'Optativus' + , 'imp! ': 'Imperativus' + , 'ptc ': 'Participium' + , 'inf ': 'Infinitivus' + }; break; + case 2: + buts = { 'act ': 'Activum' + , 'med ': 'Medium' + , 'pass ': 'Passivum' + }; break; + case 3: + if (val.match(/ inf /)) { + /* no buttons */ + } else if (val.match(/ ptc /)) { + buts = { + 'M nom ev': 'M nom ev', + 'F nom ev': 'F nom ev', + 'N nom ev': 'N nom ev', + 'M gen ev': 'M gen ev', + 'F gen ev': 'F gen ev', + 'N gen ev': 'N gen ev', + 'M dat ev': 'M dat ev', + 'F dat ev': 'F dat ev', + 'N dat ev': 'N dat ev', + 'M acc ev': 'M acc ev', + 'F acc ev': 'F acc ev', + 'N acc ev': 'N acc ev', + 'M nom mv': 'M nom mv', + 'F nom mv': 'F nom mv', + 'N nom mv': 'N nom mv', + 'M gen mv': 'M gen mv', + 'F gen mv': 'F gen mv', + 'N gen mv': 'N gen mv', + 'M dat mv': 'M dat mv', + 'F dat mv': 'F dat mv', + 'N dat mv': 'N dat mv', + 'M acc mv': 'M acc mv', + 'F acc mv': 'F acc mv', + 'N acc mv': 'N acc mv' + }; + } else { + buts = { + '1 ev': '1 ev', + '2 ev': '2 ev', + '3 ev': '3 ev', + '1 mv': '1 mv', + '2 mv': '2 mv', + '3 mv': '3 mv', + }; + } + break; + } + + var input_field = $('#trainer-input-fancy'); + + var i = 0; + for (k in buts) { + var but = $('<button></button>'); + but.addClass('btn btn-default').attr('role', 'button'); + if (Object.keys(buts).length > 6) + but.addClass('ptc'); + but.text(buts[k]).val(k); + but.click(val, function(ev){ + var ip = $('#trainer-input-'+input_count); + ip.val(ip.val() + $(this).val()).focus(); + if (step < (ev.data.match(/ inf /) ? 2 : 3)) { + stepFancyInput(step + 1, ip.val()); + } else { + var done = checkInput(true); + if ($('#trainer-input-'+input_count).parent().hasClass('has-error')) { + var next = $('<button></button>'); + next.addClass('btn btn-warning').attr('role', 'button'); + next.click(reloadVerb); + if (done) { + next.text('Next'); + } else { + next.text('Skip'); + } + $('#trainer-input-fancy').html(next); + } + } + }); + + input_field.append(but); + + if (Object.keys(buts).length > 6) { + if (!(++i % 3)) + input_field.append($('<br>')); + } else { + input_field.append($('<br>')); + } + } + } + + function addInput() { + input_count++; + var html = "<div class='row trainer-input'>\ + <div class='col-md-12'>\ + <div class='form-group'>\ + <label for='trainer-input-"+input_count+"'>Determineer:</label>\ + <input type='text' class='form-control' id='trainer-input-"+input_count+"' placeholder='Bijvoorbeeld: pr ind act 1 ev' spellcheck='false'/>\ + </div>\ + </div>\ + </div>"; + $('#trainer-input-container').append(html); + + $('#trainer-input-'+input_count).keyup(function(e){ + if (e.keyCode == 13) { + if (!checked) { + checked = checkInput(false); + } else { + reloadVerb(); + $(this) + .val('') + .css({backgroundColor:'transparent'}) + .parent().removeClass('has-error has-success'); + checked = false; + } + } else { + $(this) + .css({backgroundColor:'transparent'}) + .parent().removeClass('has-error has-success'); + checked = false; + processInput(); + } + }).focus(); + + stepFancyInput(0, ''); + } + + function removeInputs() { + $('.trainer-input').remove(); + input_count = 0; + } + + function reloadVerb() { + $('#trainer-404').hide(); + $('#trainer-verb').css({color: 'gray'}); + $('#trainer-answer').text(''); + removeInputs(); + + var modes = $('input[name="mode"]:checked').map(function(){return this.value;}); + var tenses = $('input[name="tense"]:checked').map(function(){return this.value;}); + var voices = $('input[name="voice"]:checked').map(function(){return this.value;}); + + $.ajax('form/random/', { + method: 'POST', + data: { + _token: $('#csrf').val(), + mode: $.makeArray(modes).join(), + tense: $.makeArray(tenses).join(), + voice: $.makeArray(voices).join() + }, + dataType: 'json', + error: function(jqxhr, status, error) { + $('#trainer-404').fadeIn(); + }, + success: function(data, status, jqxhr) { + $('#trainer-verb').text(data.form.form).css({color: 'black'}); + + correct_answers = []; + for (var i in data.answers) { + var answer = { + tense: data.answers[i].tense, + mode: data.answers[i].mode, + voice: data.answers[i].voice, + person: data.answers[i].person, + gender: data.answers[i].gender, + number: data.answers[i].number, + case_: data.answers[i]['case'] + }; + correct_answers.push(answer); + } + + addInput(); + } + }); + } + + var modes = []; + var tenses = []; + var tenses_abbr = []; + + function findTense(tense) { + switch (tense) { + case 'pr': return 'praesens'; + case 'impf': return 'imperfectum'; + case 'aor': return 'aoristus'; + case 'fut': return 'futurum'; + case 'pf': return 'perfectum'; + case 'pqpf': return 'plusquamperfectum'; + default: return undefined; + } + } + + function findMode(mode) { + switch (mode) { + case 'ind': return 'indicativus'; + case 'conj': return 'conjunctivus'; + case 'opt': return 'optativus'; + case 'imp!': return 'imperativus'; + default: return undefined; + } + } + + function findVoice(voice) { + switch (voice) { + case 'act': return 'A'; + case 'med': return 'M'; + case 'pass': return 'P'; + default: return undefined; + } + } + + function parseAnswer(parsing) { + var match = parsing.match(/^\s*(pr|impf|aor|fut|pf|pqpf)\s+(ind|conj|opt|imp!)\s+(act|med|pass)\s+([123])\s*([em]v)\s*$/); + if (match) { + var tense = findTense(match[1]); + var mode = findMode(match[2]); + var voice = findVoice(match[3]); + + if (typeof tense=='undefined' || typeof mode=='undefined' || typeof voice=='undefined') + return false; + + return { + tense: tense, + mode: mode, + voice: voice, + person: match[4], + gender: null, + number: match[5] == 'ev' ? 'sg' : 'pl', + case_: null + }; + } + + match = parsing.match(/^\s*(pr|impf|aor|fut|pf|pqpf)\s+ptc\s+(act|med|pass)\s+([MFN])\s+(nom|gen|dat|acc)\s+([em]v)\s*$/); + if (match) { + var tense = findTense(match[1]); + var voice = findVoice(match[2]); + + if (typeof tense=='undefined' || typeof voice=='undefined') + return false; + + return { + tense: tense, + mode: 'participium', + voice: voice, + person: null, + gender: match[3], + number: match[5] == 'ev' ? 'sg' : 'pl', + case_: match[4] + }; + } + + match = parsing.match(/^\s*(pr|impf|aor|fut|pf|pqpf)\s+inf\s+(act|med|pass)\s*$/); + if (match) { + var tense = findTense(match[1]); + var voice = findVoice(match[2]); + + if (typeof tense=='undefined' || typeof voice=='undefined') + return false; + + return { + tense: tense, + mode: 'infinitivus', + voice: voice, + person: null, + gender: null, + number: null, + case_: null + }; + } + + return false; + } + + function abbreviate(term) { + switch (term) { + case 'praesens': return 'pr'; + case 'imperfectum': return 'impf'; + case 'aoristus': return 'aor'; + case 'futurum': return 'fut'; + case 'perfectum': return 'pf'; + case 'plusquamperfectum': return 'pqpf'; + case 'indicativus': return 'ind'; + case 'conjunctivus': return 'conj'; + case 'optativus': return 'opt'; + case 'imperativus': return 'imp!'; + case 'participium': return 'ptc'; + case 'infinitivus': return 'inf'; + default: return term; + } + } + + function parsingToString(parsing) { + var tense = parsing.tense; + var mode = parsing.mode; + var voice; + switch (parsing.voice) { + case 'A': voice = 'act'; break; + case 'M': voice = 'med'; break; + case 'P': voice = 'pass'; break; + default: voice = parsing.voice; + } + var number = parsing.number == 'sg' ? 'ev' : 'mv'; + var tense_mode_voice = [tense, mode, voice].join(' '); + + switch (parsing.mode) { + case 'infinitivus': + return tense_mode_voice; + case 'participium': + return [tense_mode_voice, parsing.gender, parsing.case_, number].join(' '); + default: + return [tense_mode_voice, parsing.person, number].join(' '); + } + } + + function processInput() { + var input = $('#trainer-input-' + input_count); + var answer = parseAnswer(input.val()); + if (answer === false) { + input.parent().addClass('has-error'); + } else { + input.parent().removeClass('has-error'); + } + return answer; + } + + function checkInput(reload) { + var answer = processInput(); + for (var i in correct_answers) { + var correct_answer = correct_answers[i]; + var json = JSON.stringify(correct_answer); + if (JSON.stringify(answer) == json) { + $('#trainer-input-'+input_count) + .css({backgroundColor: '#dff0d8'}) + .parent().addClass('has-success'); + if ($('#settings-audio').prop('checked')) audio_positive.play(); + + correct_answers.splice(i,1); + if (correct_answers.length > 0) { + addInput(); + return false; + } else { + if (reload === true) { + window.setTimeout(reloadVerb, 600); + } + return true; + } + } + } + + $('#trainer-input-'+input_count) + .css({backgroundColor: '#f2dede'}) + .parent().addClass('has-error'); + if ($('#settings-audio').prop('checked')) audio_negative.play(); + $('#trainer-answer').text(' - ' + correct_answers.map(parsingToString).join(', ')); + + return true; + } + + function init() { + $.ajax('mode/', { + dataType: 'json', + success: function(data, status, jqxhr) { + modes = data.map(function(d){return d.name;}); + } + }); + + $.ajax('tense/', { + dataType: 'json', + success: function(data, status, jqxhr) { + tenses = data.map(function(d){return d.name;}); + tenses_abbr = data.map(function(d){return d.abbreviation;}); + } + }); + + if (typeof reload_on_load != 'undefined' && reload_on_load) + reloadVerb(); + } + + $('#luoparsetrainer-settings .reload-verb').change(function(){ + reloadVerb(); + }); + + var help_shown = false; + $('#show-hide-help').click(function(){ + help_shown = !help_shown; + $('#trainer-input-help').slideToggle(); + $(this).text(help_shown ? 'Verberg' : 'Meer informatie'); + $('#trainer-input-'+input_count).focus(); + }); + + init(); +}); diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php index 98871e1..73f7b61 100644 --- a/resources/views/layouts/master.blade.php +++ b/resources/views/layouts/master.blade.php @@ -23,8 +23,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. <title>λύω-trainer</title> - <link rel="stylesheet" href="{{ asset('vendor/twbs/bootstrap/dist/css/bootstrap.min.css') }}"/> - <link rel="stylesheet" href="{{ asset('public/css/luoparsetrainer.css') }}"/> + <link rel="stylesheet" href="{{ asset('css/bootstrap.min.css') }}"/> + <link rel="stylesheet" href="{{ asset('css/luoparsetrainer.css') }}"/> <script type="text/javascript"> var app_url = '{{ env('APP_URL') }}'; @@ -40,8 +40,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. @yield('master-content') </div> - <script src="{{ asset('vendor/components/jquery/jquery.min.js') }}"></script> - <script src="{{ asset('vendor/twbs/bootstrap/dist/js/bootstrap.min.js') }}"></script> - <script src="{{ asset('public/js/luoparsetrainer.js') }}"></script> + <script src="{{ asset('js/app.js') }}"></script> </body> </html> |