From 9c84cb67d2b1537de440c1d1e623d86b5d171642 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Mon, 9 May 2016 21:27:00 +0200 Subject: Buttons for answer input --- public/css/hebrewparsetrainer.css | 18 +- public/js/hebrewparsetrainer.js | 596 +++++++++++++++++++++----------------- resources/views/trainer.php | 148 +++++----- 3 files changed, 419 insertions(+), 343 deletions(-) diff --git a/public/css/hebrewparsetrainer.css b/public/css/hebrewparsetrainer.css index 1776cf3..54f0c2d 100644 --- a/public/css/hebrewparsetrainer.css +++ b/public/css/hebrewparsetrainer.css @@ -16,23 +16,27 @@ * along with this program. If not, see . */ @font-face { - font-family: 'Ezra SIL'; - src: url('fonts/EzraSIL.ttf'); + font-family: 'Ezra SIL'; + src: url('fonts/EzraSIL.ttf'); } #trainer-404 { - display: none; - padding: 15px; + display: none; + padding: 15px; +} + +#trainer-input-fancy { + margin-bottom: 20px; } #trainer-input-help { - display: none; + display: none; } .hebrew { - font-family: 'Ezra SIL', David; + font-family: 'Ezra SIL', David; } .hebrew-large { - font-size: 40px; + font-size: 40px; } diff --git a/public/js/hebrewparsetrainer.js b/public/js/hebrewparsetrainer.js index b453458..ea4e571 100644 --- a/public/js/hebrewparsetrainer.js +++ b/public/js/hebrewparsetrainer.js @@ -16,267 +16,337 @@ * 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 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(); - } 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(); - } - - function removeInputs() { - $('.trainer-input').remove(); - input_count = 0; - } - - function reloadVerb() { - $('#trainer-404').hide(); - $('#trainer-verb').css({color: 'gray'}); - $('#trainer-answer').text(''); - removeInputs(); - - var stems = $('input[name="stem"]:checked').map(function(){return this.value;}); - var tenses = $('input[name="tense"]:checked').map(function(){return this.value;}); - var roots = $('input[name="root"]:checked').map(function(){return this.value;}); - - $.ajax('verb/random/', { - data: { - stem: $.makeArray(stems).join(), - tense: $.makeArray(tenses).join(), - root: $.makeArray(roots).join() - }, - dataType: 'json', - error: function(jqxhr, status, error) { - $('#trainer-404').fadeIn(); - }, - success: function(data, status, jqxhr) { - $('#trainer-verb').text(data.verb.verb).css({color: 'black'}); - - correct_answers = []; - for (var i in data.answers) { - var answer = { - stem: data.answers[i].stem, - tense: data.answers[i].tense, - person: data.answers[i].person, - gender: data.answers[i].gender, - number: data.answers[i].number - }; - correct_answers.push(answer); - } - - addInput(); - } - }); - } - - var stems = []; - var tenses = []; - var tenses_abbr = []; - - function findStem(stem) { - var stems_ = stems.filter(function(s){return s.toLowerCase().indexOf(stem.toLowerCase()) == 0;}); - if (stems_.length == 1) - return stems_[0]; - } - - function findTense(tense) { - if (tenses.indexOf(tense) != -1) - return tense; - if (tenses_abbr.indexOf(tense) != -1) - return tenses[tenses_abbr.indexOf(tense)]; - } - - function parseAnswer(parsing) { - var persons = ['1', '2', '3', null]; - var genders = ['m', 'f', 'c', null]; - var numbers = ['s', 'p', null]; - - var re = /^\s*(\w+)\s+(\w+)(?:\s+(?:([123])\s*)?([mf])\s*([sp])\s*)?$/; - var match = parsing.match(re); - if (match == null) - return false; - - var stem = findStem(match[1]); - var tense = findTense(match[2]); - var person = match[3] ? match[3] : null; - var gender = match[4] ? match[4] : null; - var number = match[5] ? match[5] : null; - - if (typeof stem === 'undefined' || typeof tense === 'undefined' || $.inArray(person, persons) == -1 || - $.inArray(gender, genders) == -1 || $.inArray(number, numbers) == -1) - return false; - - if (tense.indexOf('infinitive') == 0 && (person != null || gender != null || number != null)) - return false; - if (tense.indexOf('infinitive') != 0) { - if (gender == null || number == null) - return false; - if (tense.indexOf('participle') == 0 && person != null) - return false; - if (tense.indexOf('participle') != 0 && person == null) - return false; - } - - return { - stem: stem, - tense: tense, - person: person, - gender: gender, - number: number - }; - } - - function parsingToString(parsing, extended) { - var genders = { - 'm': 'masculine', - 'f': 'feminine' - }; - var numbers = { - 's': 'singular', - 'p': 'plural' - }; - if (extended === true) { - return parsing.stem + ' ' + parsing.tense + - (parsing.person ? (' ' + parsing.person) : '') + - (parsing.gender ? (' ' + genders[parsing.gender]) : '') + - (parsing.number ? (' ' + numbers[parsing.number]) : ''); - } else { - return parsing.stem + ' ' + parsing.tense + - (parsing.person ? (' ' + parsing.person) : '') + - (parsing.gender ? (' ' + parsing.gender) : '') + - (parsing.number ? (' ' + parsing.number) : ''); - } - } - - 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('Parsing error'); - } else { - input.parent().removeClass('has-error'); - $('#trainer-parsed-' + input_count).val(parsingToString(answer, true)); - } - return answer; - } - - function checkInput() { - 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]; - if (JSON.stringify(answer) == JSON.stringify(correct_answer)) { - $('#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 { - 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('stem/', { - dataType: 'json', - success: function(data, status, jqxhr) { - stems = 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;}); - } - }); - - reloadVerb(); - } - - $('#hebrewparsetrainer-settings input.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(); + // 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) { + $('#trainer-input-fancy').html(''); + var buts = {}; + switch (step) { + case 0: + buts = { 'Q ': 'Qal' + , 'Hip ': 'Hiphil' + , 'Ho ': 'Hophal' + , 'Ni ': 'Niphal' + , 'Pi ': 'Piel' + , 'Pu ': 'Pual' + , 'Hit ': 'Hitpael' + }; break; + case 1: + buts = { 'pf ': 'Pf.' + , 'ipf ': 'Ipf.' + , 'coh ': 'Coh.' + , 'imp ': 'Imp.' + , 'ius ': 'Ius.' + , 'infcs': 'Inf. cs.' + , 'infabs': 'Inf. abs.' + , 'pta ': 'Part. act.' + , 'ptp ': 'Part. pass.' + }; break; + case 2: + buts = { '1': '1', '2': '2', '3': '3', '': 'N/A' }; break; + case 3: + buts = { 'm': 'Masculine', 'f': 'Feminine', '': 'N/A' }; break; + case 4: + buts = { 's': 'Singular', 'p': 'Plural', '': 'N/A' }; break; + } + + 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 < 4) { + stepFancyInput(step + 1); + } else { + var done = checkInput(true); + if ($('#trainer-input-'+input_count).parent().hasClass('has-error')) { + if (done) { + var next = $(''); + next.addClass('btn btn-warning').attr('role', 'button'); + next.text('Next'); + next.click(reloadVerb); + $('#trainer-input-fancy').html(next); + } else { + var skip = $(''); + skip.addClass('btn btn-warning').attr('role', 'button'); + skip.text('Skip'); + skip.click(reloadVerb); + $('#trainer-input-fancy').append(skip); + } + } + } + }); + + $('#trainer-input-fancy').append(but).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 stems = $('input[name="stem"]:checked').map(function(){return this.value;}); + var tenses = $('input[name="tense"]:checked').map(function(){return this.value;}); + var roots = $('input[name="root"]:checked').map(function(){return this.value;}); + + $.ajax('verb/random/', { + data: { + stem: $.makeArray(stems).join(), + tense: $.makeArray(tenses).join(), + root: $.makeArray(roots).join() + }, + dataType: 'json', + error: function(jqxhr, status, error) { + $('#trainer-404').fadeIn(); + }, + success: function(data, status, jqxhr) { + $('#trainer-verb').text(data.verb.verb).css({color: 'black'}); + + correct_answers = []; + for (var i in data.answers) { + var answer = { + stem: data.answers[i].stem, + tense: data.answers[i].tense, + person: data.answers[i].person, + gender: data.answers[i].gender, + number: data.answers[i].number + }; + correct_answers.push(answer); + } + + addInput(); + } + }); + } + + var stems = []; + var tenses = []; + var tenses_abbr = []; + + function findStem(stem) { + var stems_ = stems.filter(function(s){return s.toLowerCase().indexOf(stem.toLowerCase()) == 0;}); + if (stems_.length == 1) + return stems_[0]; + } + + function findTense(tense) { + if (tenses.indexOf(tense) != -1) + return tense; + if (tenses_abbr.indexOf(tense) != -1) + return tenses[tenses_abbr.indexOf(tense)]; + } + + function parseAnswer(parsing) { + var persons = ['1', '2', '3', null]; + var genders = ['m', 'f', 'c', null]; + var numbers = ['s', 'p', null]; + + var re = /^\s*(\w+)\s+(\w+)(?:\s+(?:([123])\s*)?([mf])\s*([sp])\s*)?$/; + var match = parsing.match(re); + if (match == null) + return false; + + var stem = findStem(match[1]); + var tense = findTense(match[2]); + var person = match[3] ? match[3] : null; + var gender = match[4] ? match[4] : null; + var number = match[5] ? match[5] : null; + + if (typeof stem === 'undefined' || typeof tense === 'undefined' || $.inArray(person, persons) == -1 || + $.inArray(gender, genders) == -1 || $.inArray(number, numbers) == -1) + return false; + + if (tense.indexOf('infinitive') == 0 && (person != null || gender != null || number != null)) + return false; + if (tense.indexOf('infinitive') != 0) { + if (gender == null || number == null) + return false; + if (tense.indexOf('participle') == 0 && person != null) + return false; + if (tense.indexOf('participle') != 0 && person == null) + return false; + } + + return { + stem: stem, + tense: tense, + person: person, + gender: gender, + number: number + }; + } + + function parsingToString(parsing, extended) { + var genders = { + 'm': 'masculine', + 'f': 'feminine' + }; + var numbers = { + 's': 'singular', + 'p': 'plural' + }; + if (extended === true) { + return parsing.stem + ' ' + parsing.tense + + (parsing.person ? (' ' + parsing.person) : '') + + (parsing.gender ? (' ' + genders[parsing.gender]) : '') + + (parsing.number ? (' ' + numbers[parsing.number]) : ''); + } else { + return parsing.stem + ' ' + parsing.tense + + (parsing.person ? (' ' + parsing.person) : '') + + (parsing.gender ? (' ' + parsing.gender) : '') + + (parsing.number ? (' ' + parsing.number) : ''); + } + } + + 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('Parsing error'); + } 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]; + if (JSON.stringify(answer) == JSON.stringify(correct_answer)) { + $('#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('stem/', { + dataType: 'json', + success: function(data, status, jqxhr) { + stems = 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;}); + } + }); + + reloadVerb(); + } + + $('#hebrewparsetrainer-settings input.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(); }); diff --git a/resources/views/trainer.php b/resources/views/trainer.php index cec745d..b9fef0e 100644 --- a/resources/views/trainer.php +++ b/resources/views/trainer.php @@ -17,83 +17,85 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . --> - - - HebrewParseTrainer - - - - - -
- + + + HebrewParseTrainer + + + + + +
+ -
-
-
-
-

Stems

- name; ?> -
- -
- -
+
+
+ +
+

Stems

+ name; ?> +
+ +
+ +
-
-

Tenses

- name; ?> -
- -
- -
+
+

Tenses

+ name; ?> +
+ +
+ +
-
-

Roots

- root; ?> -
- -
- -
+
+

Roots

+ root; ?> +
+ +
+ +
-
-

Settings

-
- -
-
+
+

Settings

+
+ +
+
-

About

-

© 2015 Camil Staps. Licensed under GPL 3.0. Source is on GitHub.

- -
-
-

There are no verbs matching the criteria in our database.

-

-
-
-
-

Parse the verb and enter the answer as described below. Press return. If your answer was correct and there are multiple possible parsings, an extra input field will appear. After the first incorrect answer or after entering all possible answers, you can continue to the next verb by pressing return once more.

-

- Stems: either use the full name or a significant beginning (i.e. Q for Qal but Pi for Piel rather than P).
- Tenses: use the abbreviations pf, ipf, coh, imp, jus, infcs, infabs, pta and ptp.
- Person: 1, 2, 3 or none (infinitives and participles).
- Gender: m, f or none (infinitives).
- Number: s, p or none (infinitives). -

-

Examples: Q pf 3ms, ni pta fp, pi infabs.

-
- -
-
-
+

About

+

© 2015 Camil Staps. Licensed under GPL 3.0. Source is on GitHub.

+ +
+
+

There are no verbs matching the criteria in our database.

+

+
+
+
+
+

Parse the verb and enter the answer as described below. Press return. If your answer was correct and there are multiple possible parsings, an extra input field will appear. After the first incorrect answer or after entering all possible answers, you can continue to the next verb by pressing return once more.

+

+ Stems: either use the full name or a significant beginning (i.e. Q for Qal but Pi for Piel rather than P).
+ Tenses: use the abbreviations pf, ipf, coh, imp, jus, infcs, infabs, pta and ptp.
+ Person: 1, 2, 3 or none (infinitives and participles).
+ Gender: m, f or none (infinitives).
+ Number: s, p or none (infinitives). +

+

Examples: Q pf 3ms, ni pta fp, pi infabs.

+

You can also use the buttons to enter your answer. This is an experimental feature.

+
+ +
+
+
- - - - + + + + -- cgit v1.2.3