From ad10a6467f76822b9289832eeb0d0ac2038b32d1 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Mon, 30 Dec 2019 16:57:13 +0100 Subject: Strip down for simple app for Greek verb λύω --- public/js/luoparsetrainer.js | 436 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 public/js/luoparsetrainer.js (limited to 'public/js/luoparsetrainer.js') diff --git a/public/js/luoparsetrainer.js b/public/js/luoparsetrainer.js new file mode 100644 index 0000000..11394e4 --- /dev/null +++ b/public/js/luoparsetrainer.js @@ -0,0 +1,436 @@ +/** + * Luo Parse Trainer - practice Ancient Greek verb forms + * Copyright (C) 2015-present Camil Staps + * + * 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 . + */ +$(document).ready(function(){ + // http://stackoverflow.com/a/4399433/1544337 + jQuery.fn.shake = function(intShakes, intDistance, intDuration) { + this.each(function() { + $(this).css("position","relative"); + for (var x=1; x<=intShakes; x++) { + $(this).animate({left:(intDistance*-1)}, (intDuration/intShakes)/4) + .animate({left:intDistance}, (intDuration/intShakes)/2) + .animate({left:0}, (intDuration/intShakes)/4); + } + }); + return this; + }; + + 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 = { 'A ': 'Activum' + , 'M ': 'Medium' + , 'P ': 'Passivum' + , 'MP ': 'Medio-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', + 'N acc ev': 'N acc ev', + 'F acc ev': 'F 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 = $(''); + but.addClass('btn btn-default').attr('role', 'button'); + but.text(buts[k]).val(k); + but.click(function(){ + var ip = $('#trainer-input-'+input_count); + ip.val(ip.val() + $(this).val()).focus(); + if (step < 3) { + stepFancyInput(step + 1, ip.val()); + } else { + var done = checkInput(true); + if ($('#trainer-input-'+input_count).parent().hasClass('has-error')) { + var next = $(''); + 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).append(' '); + + if (Object.keys(buts).length > 6 && !(++i % 3)) + input_field.append($('
')); + } + } + + function addInput() { + input_count++; + var html = "
\ +
\ +
\ + \ + \ +
\ +
\ +
\ +
\ + \ + \ +
\ +
\ +
"; + $('#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;}); + + $.ajax('form/random/', { + method: 'POST', + data: { + _token: $('#csrf').val(), + mode: $.makeArray(modes).join(), + tense: $.makeArray(tenses).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 parseAnswer(parsing) { + var match = parsing.match(/^\s*(pr|impf|aor|fut|pf|pqpf)\s+(ind|conj|opt|imp!)\s+(A|M|P|MP)\s+([123])\s*([em]v)\s*$/); + if (match) { + var tense = findTense(match[1]); + var mode = findMode(match[2]); + + if (typeof tense=='undefined' || typeof mode=='undefined') + return false; + + return { + tense: tense, + mode: mode, + voice: match[3], + 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+(A|M|P|MP)\s+([MFN])\s+(nom|gen|dat|acc)\s+([em]v)\s*$/); + if (match) { + var tense = findTense(match[1]); + + if (typeof tense=='undefined') + return false; + + return { + tense: tense, + mode: 'participium', + voice: match[2], + 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+(A|M|P|MP)\s*$/); + if (match) { + var tense = findTense(match[1]); + + if (typeof tense=='undefined') + return false; + + return { + tense: tense, + mode: 'infinitivus', + voice: match[2], + 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, abbr) { + var tense = abbr === true ? abbreviate(parsing.tense) : parsing.tense; + var mode = abbr === true ? abbreviate(parsing.mode) : parsing.mode; + var number = parsing.number == 'sg' ? 'ev' : 'mv'; + var tense_mode_voice = [tense, mode, parsing.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'); + $('#trainer-parsed-' + input_count).val( + input.val().length < 10 ? 'Vul een volledige parsering in...' : 'Incorrecte invoer'); + } else { + input.parent().removeClass('has-error'); + $('#trainer-parsed-' + input_count).val(parsingToString(answer, true)); + } + return answer; + } + + function checkInput(reload) { + var answer = processInput(); + if (!answer && $('#trainer-input-'+input_count).val() != '') { + $('#trainer-input-'+input_count).shake(2, 12, 300); + return false; + } + + 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 ? 'Hide' : 'Show') + ' help'); + $('#trainer-input-'+input_count).focus(); + }); + + init(); +}); -- cgit v1.2.3