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.wavBinary files differ new file mode 100644 index 0000000..8718ca9 --- /dev/null +++ b/resources/audio/negative.wav diff --git a/resources/audio/positive.wav b/resources/audio/positive.wavBinary files differ new 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.ttfBinary files differ new 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> | 
