Skip to content

Instantly share code, notes, and snippets.

@gorbiz
Last active February 18, 2016 13:46
Show Gist options
  • Select an option

  • Save gorbiz/a46c385c52ae745760b6 to your computer and use it in GitHub Desktop.

Select an option

Save gorbiz/a46c385c52ae745760b6 to your computer and use it in GitHub Desktop.
Grammatica Latina
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Grammatica Latina</title>
<link href='https://fonts.googleapis.com/css?family=Cinzel' rel='stylesheet' type='text/css'>
<style>
* { font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; }
th, p, p *, #counter { font-family: 'Cinzel', serif; }
.demo td, th { padding: .25em; }
.demo th {
text-align: left;
padding-right: 1em;
padding-left: 0.5em;
background: #f0f0f0;
}
input { border-color: transparent; }
input[type="text"] {
width: 14em;
font-size: 1.1em;
}
input.correct { background-color: #cfc; }
input.correct-macrons { border-bottom-color: #0f0; }
input[readonly] { background: transparent; }
input[type="submit"] { display: none; }
.reveal-on-hover {
visibility: hidden;
}
.secret-box:hover .reveal-on-hover {
visibility: visible;
}
p.secret-box {
margin: 0.5em;
}
#counter {
position: fixed;
top: 0;
right: 1em;
font-size: 1.75em;
font-weight: bold;
color: #555;
}
.help-chart {
width: 100%;
}
</style>
<script type="text/template" id="noun-form">
<form id="noun-adj-form" onsubmit="return next();">
<table class="demo">
<caption></caption>
<thead>
<tr>
<th>Kasus</th>
<th>Singular</th>
<th>Plural</th>
</tr>
</thead>
<tbody>
<tr>
<th>nominative</th>
<td><input type="text" correct="%nom%" required autofocus /></td>
<td><input type="text" correct="%nom_pl%" required /></td>
</tr>
<tr>
<th>genitiv</th>
<td><input type="text" correct="%gen%" value="%gen%" readonly disabled /></td>
<td><input type="text" correct="%gen_pl%" value="%gen_pl%" readonly disabled /></td>
</tr>
<tr>
<th>dativ</th>
<td><input type="text" correct="%dat%" value="%dat%" readonly disabled /></td>
<td><input type="text" correct="%dat_pl%" value="%dat_pl%" readonly disabled /></td>
</tr>
<tr>
<th>ackusativ</th>
<td><input type="text" correct="%acc%" required /></td>
<td><input type="text" correct="%acc_pl%" required /></td>
</tr>
<tr>
<th>ablativ</th>
<td><input type="text" correct="%abl%" value="%abl%" readonly disabled /></td>
<td><input type="text" correct="%abl_pl%" value="%abl_pl%" readonly disabled /></td>
</tr>
<tbody>
</table>
<p class="secret-box">Declension: <strong class="reveal-on-hover">%dec%</strong></p>
<p class="secret-box">Gender: <strong class="reveal-on-hover">%gender%</strong></p>
<input type="submit" value="Submit" />
</form>
<img src="latin-declensions.png" alt="Latin declensions chart" class="help-chart" />
</script>
<script type="text/words" id="noun-adj-1" guess="nom,acc">
1, 1/2 declension.
feminine gender
Case Singular Plural
nominative puella laeta puellae laetae
genitive puellae laetae puellārum laetārum
dative puellae laetae puellīs laetīs
accusative puellam laetam puellās laetās
ablative puellā laetā puellīs laetīs
vocative puella laeta puellae laetae
2, 1/2 declension.
masculine gender
Case Singular Plural
nominative amīcus ānxius amīcī ānxiī
genitive amīcī ānxiī amīcōrum ānxiōrum
dative amīcō ānxiō amīcīs ānxiīs
accusative amīcum ānxium amīcōs ānxiōs
ablative amīcō ānxiō amīcīs ānxiīs
vocative amīce ānxie amīcī ānxiī
2, 2 declension.
neuter gender
Case Singular Plural
nominative vīnum bonum vīna bona
genitive vīnī bonī vīnōrum bonōrum
dative vīnō bonō vīnīs bonīs
accusative vīnum bonum vīna bona
ablative vīnō bonō vīnīs bonīs
vocative vīnum bonum vīna bona
3, 3 declension.
masculine gender
Case Singular Plural
nominative pater fēlīx patrēs fēlīcēs
genitive patris fēlīcis patrum fēlīcium
dative patrī fēlīcī patribus fēlīcibus
accusative patrem fēlīcem patrēs fēlīcēs
ablative patre fēlīcī patribus fēlīcibus
vocative pater fēlīx patrēs fēlīcēs
3, 3 declension.
masculine gender
Case Singular Plural
nominative coniūnx sapiēns coniugēs sapientēs
genitive coniugis sapientis coniugum sapientium
dative coniugī sapientī coniugibus sapientibus
accusative coniugem sapientem coniugēs sapientēs
ablative coniuge sapientī coniugibus sapientibus
vocative coniūnx sapiēns coniugēs sapientēs
3, 3 (i-stem) declension neuter.
neuter gender
Case Singular Plural
nominative nūmen ingēns nūmina ingentia
genitive nūminis ingentis nūminum ingentium
dative nūminī ingentī nūminibus ingentibus
accusative nūmen ingēns nūmina ingentia
ablative nūmine ingentī nūminibus ingentibus
vocative nūmen ingēns nūmina ingentia
2, 3 declension.
masculine gender
Case Singular Plural
nominative amīcus fēlīx amīcī fēlīcēs
genitive amīcī fēlīcis amīcōrum fēlīcium
dative amīcō fēlīcī amīcīs fēlīcibus
accusative amīcum fēlīcem amīcōs fēlīcēs
ablative amīcō fēlīcī amīcīs fēlīcibus
vocative amīce fēlīx amīcī fēlīcēs
3, 1/2 declension.
feminine gender
Case Singular Plural
nominative coniūnx ānxia coniugēs ānxiae
genitive coniugis ānxiae coniugum ānxiārum
dative coniugī ānxiae coniugibus ānxiīs
accusative coniugem ānxiam coniugēs ānxiās
ablative coniuge ānxiā coniugibus ānxiīs
vocative coniūnx ānxia coniugēs ānxiae
</script>
</head>
<body>
<p id="counter"></p>
<div id="wrap"></div>
</body>
<script src="latin.js" charset="utf-8"></script>
<script>
var words = parse(document.getElementById('noun-adj-1').innerText);
var index = 0;
function next() {
if (index++ == 0) words = shuffle(words);
if (index >= words.length) index = 0;
document.getElementById('wrap').innerHTML = template('noun-form', words[index]);
document.querySelector('[autofocus]').focus();
document.getElementById('counter').innerHTML = (index+1) + ' / ' + words.length;
// check answer onBlur
[].forEach.call(document.querySelectorAll('input[type=text]'), function(inp) {
inp.onblur = function(e) {
var t = e.target;
var answer = t.value;
var correct = t.getAttribute('correct');
t.classList.toggle('correct', removeMacrons(answer) == removeMacrons(correct));
t.classList.toggle('correct-macrons', answer == correct);
}
});
return false;
}
next();
</script>
</html>
function shuffle(array) {
var tmp, current, top = array.length;
if (top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
function removeMacrons(text) {
return text.replace(/ā/g,'a').replace(/Ã/g,'A')
.replace(/ē/g,'e').replace(/Ē/g,'E')
.replace(/ī/g,'i').replace(/Ī/g,'I')
.replace(/ō/g,'o').replace(/Õ/g,'O')
.replace(/ū/g,'u').replace(/Ū/g,'U');
}
function parse(text) {
return text.trim().split('\n\n').map(wordObjectFrom);
}
function wordObjectFrom(text) {
text = text.toLowerCase();
var o = {};
['nominative', 'genitive', 'dative', 'accusative', 'ablative'/*, 'vocative'*/].map(function(caze) {
var res = (new RegExp(caze + '\\s+(.+?)\\s\\s+(.+)', 'g')).exec(text);
if (!res) throw new Error('could not find "' + caze + '" in text');
o[caze.substr(0, 3)] = res[1];
o[caze.substr(0, 3) + '_pl'] = res[2];
});
o.gender = (/(.+)\sgender/g.exec(text) || ['', '?'])[1];
o.dec = (/\s*(.+)\sdeclension/g.exec(text) || ['', false])[1];
if (!o.dec) console.warn('declension not found');
return o;
}
function template(templateid, data) {
return document.getElementById(templateid).innerHTML.replace(/%(\w*)%/g, function(m, key){return data.hasOwnProperty(key)?data[key]:'';});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment