Commit e68c5a02 authored by Björn Eyselein's avatar Björn Eyselein
Browse files

Update Flashcards: Double backs

parent 11dc9cbd
package model
import model.levenshtein.EditOperation
final case class StringSolution(id: Int, solution: String)
final case class Solution(
......
......@@ -33,13 +33,20 @@ object JsonFormats {
Json.format[EditOperation]
}
private val levenshteinDistanceWrites: Writes[LevenshteinDistance] = {
def unapplyLevenshteinDistance: LevenshteinDistance => (String, String, Int) = ld => (ld.start, ld.target, ld.distance)
def unapplyLevenshteinDistance: LevenshteinDistance => (StringSolution, String, Int, Seq[EditOperation]) =
ld => (ld.start, ld.target, ld.distance, ld.backtrace)
implicit val ssw: Writes[StringSolution] = stringSolutionFormat
implicit val eow: Writes[EditOperation] = editOperationFormat
(
(__ \ "start").write[String] and
(__ \ "start").write[StringSolution] and
(__ \ "target").write[String] and
(__ \ "distance").write[Int]
(__ \ "distance").write[Int] and
(__ \ "editOperations").write[Seq[EditOperation]]
) (unapplyLevenshteinDistance)
}
......
......@@ -35,7 +35,7 @@ object Matcher {
case Nil => MatchHeadResult(priorSamples ++ posteriorSamples, maybeBestAndDistanceToBest)
case head :: tail =>
val distanceToHead = LevenshteinDistance(learnerSolution.solution, head)
val distanceToHead = LevenshteinDistance(learnerSolution, head)
maybeBestAndDistanceToBest match {
case None =>
......
package model.levenshtein
import model.StringSolution
import model.levenshtein.OperationType._
final case class LevenshteinDistance(start: String, target: String) {
final case class LevenshteinDistance(start: StringSolution, target: String) {
@inline
private def minimum(i: Int*): Int = i.min
......@@ -21,7 +22,7 @@ final case class LevenshteinDistance(start: String, target: String) {
dist
}
private def calculateBacktrace(): Seq[EditOperation] = {
private def calculateBacktrace(dist: Array[Array[Int]]): Seq[EditOperation] = {
@annotation.tailrec
def go(dist: Array[Array[Int]], i: Int, j: Int, operations: List[EditOperation]): List[EditOperation] =
......@@ -46,14 +47,14 @@ final case class LevenshteinDistance(start: String, target: String) {
} else operations
go(dist, start.length, target.length, List[EditOperation]())
go(dist, start.solution.length, target.length, List[EditOperation]())
}
private val dist = calculateTable(start, target)
private val dist = calculateTable(start.solution, target)
val distance: Int = dist(start.length)(target.length)
val distance: Int = dist(start.solution.length)(target.length)
lazy val backtrace: Seq[EditOperation] = calculateBacktrace()
lazy val backtrace: Seq[EditOperation] = calculateBacktrace(dist)
}
......@@ -7,9 +7,9 @@
}
@scripts = {
<script src="@routes.Assets.versioned("scripts/learnRepeatBasics.js")"></script>
<script src="@routes.Assets.versioned("scripts/questionMaker.js")"></script>
<script src="@routes.Assets.versioned("scripts/learnRepeat.js")"></script>
<script src="@routes.Assets.versioned("javascripts/learnRepeatBasics.js")"></script>
<script src="@routes.Assets.versioned("javascripts/questionMaker.js")"></script>
<script src="@routes.Assets.versioned("javascripts/learnRepeat.js")"></script>
}
@loadFcUrl = @{
......
......@@ -12,7 +12,6 @@ TwirlKeys.templateImports += "model.TemplateConsts._"
scalaVersion := "2.13.0"
updateOptions := updateOptions.value.withCachedResolution(cachedResoluton = true)
resolveFromWebjarsNodeModulesDir := true
val webJarDependencies = Seq(
// FIXME: remove jquery?!?
......
......@@ -8,6 +8,3 @@ addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.4.0")
// SCoverage for Scala
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1")
// Typescript compiler
addSbtPlugin("name.de-vries" % "sbt-typescript" % "2.6.2")
if ('serviceWorker' in navigator) {
console.warn('Installing service worker...');
navigator.serviceWorker.register('service-worker.js', { scope: '/' })
.then(registration => console.log(registration))
.catch(error => console.error(error));
}
//# sourceMappingURL=/assets/app.js.map
\ No newline at end of file
{"version":3,"file":"app.js","sourceRoot":"/assets/","sources":["app.ts"],"names":[],"mappings":"AAAA,IAAI,eAAe,IAAI,SAAS,EAAE;IAC9B,OAAO,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAC7C,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAC,KAAK,EAAE,GAAG,EAAC,CAAC;SAC9D,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;SAC/C,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;CAE7C"}
\ No newline at end of file
let checkSolutionBtn;
let nextFlashcardBtn;
let progressDiv;
let correctionTextPar;
let currentFlashcard = null;
let flashcards = [];
let checkSolutionUrl;
let canSolve = true;
let maxNumOfCards = 10;
let answeredFlashcards = 0;
function readSolution(cardType) {
let solutions = [];
let selectedAnswers = [];
switch (cardType) {
case 'Word':
case 'Text':
const solutionInputs = Array.from(document.querySelectorAll('.translation_input'));
solutions = solutionInputs
.map((input, index) => {
return {
id: index,
solution: input.value.trim()
};
})
.filter((solution) => solution.solution.length !== 0);
if (solutions.length === 0) {
alert('Sie können keine leere Lösung abgeben!');
return null;
}
break;
case 'Blank':
throw cardType;
case 'Choice':
selectedAnswers = Array.from(document.querySelectorAll('input[name=choice_answers]'))
.filter((element) => element.checked)
.map((element) => parseInt(element.dataset.choiceid));
if (selectedAnswers.length === 0) {
alert('Bitte wählen Sie mindestens eine Antwort aus.');
return null;
}
break;
default:
console.error('There has been an internal error: ' + cardType);
return undefined;
}
return {
cardId: currentFlashcard.flashcard.cardId,
collId: currentFlashcard.flashcard.collId,
courseId: currentFlashcard.flashcard.courseId,
solutions,
selectedAnswers,
frontToBack: currentFlashcard.frontToBack
};
}
function onCorrectionSuccess(result, cardType) {
console.info(JSON.stringify(result, null, 2));
let correctionText = `Ihre Lösung war ${result.correct ? '' : 'nicht '} korrekt.`;
if ((result.newTriesCount >= 2) && (result.maybeSampleSolution != null)) {
correctionText += ` Die korrekte Lösung lautet '<code>${result.maybeSampleSolution}</code>'.`;
}
canSolve = !(result.correct || result.newTriesCount >= 2);
correctionTextPar.innerHTML = correctionText;
correctionTextPar.classList.remove(result.correct ? 'red-text' : 'green-text');
correctionTextPar.classList.add(result.correct ? 'green-text' : 'red-text');
checkSolutionBtn.disabled = !canSolve;
nextFlashcardBtn.disabled = canSolve;
if (!canSolve) {
answeredFlashcards++;
progressDiv.style.width = `${answeredFlashcards / maxNumOfCards * 100}%`;
document.querySelector('#answeredFcCountSpan').innerHTML = answeredFlashcards.toString();
if (currentFlashcard.flashcard.cardType in ['Text', 'Word']) {
document.querySelectorAll('.translation_input').forEach((translationInput) => translationInput.disabled = true);
}
if (answeredFlashcards >= maxNumOfCards) {
nextFlashcardBtn.onclick = () => {
window.location.href = nextFlashcardBtn.dataset['endurl'];
};
nextFlashcardBtn.textContent = "Bearbeiten beenden";
}
}
document.querySelector('#triesSpan').innerText = result.newTriesCount.toString();
switch (cardType) {
case 'Word':
case 'Text':
result.matchingResult.matches.forEach((match) => {
const translationInput = document.querySelector(`#translation_input_${match.start.id}`);
const isCorrect = match.distance === 0;
translationInput.classList.remove(isCorrect ? 'invalid' : 'valid');
translationInput.classList.add(isCorrect ? 'valid' : 'invalid');
});
break;
case 'Blank':
document.querySelectorAll('.translation_input').forEach((textInput) => {
textInput.classList.remove(result.correct ? 'invalid' : 'valid');
textInput.classList.add(result.correct ? 'valid' : 'invalid');
});
break;
case 'Choice':
console.error(JSON.stringify(result.answersSelection));
break;
default:
console.error(cardType);
}
nextFlashcardBtn.focus();
}
function initialLoadNextFlashcards(loadFlashcardUrl) {
fetch(loadFlashcardUrl).then(response => {
if (response.status === 200) {
response.json().then((loadedFlashcard) => {
flashcards = loadedFlashcard;
loadNextFlashcard();
});
}
else if (response.status === 404) {
alert("Sie haben alle Karteikarten abgearbeitet.");
window.location.href = '/';
}
});
}
function loadNextFlashcard() {
if (flashcards.length > 0) {
[currentFlashcard, ...flashcards] = flashcards;
canSolve = true;
checkSolutionBtn.disabled = !canSolve;
nextFlashcardBtn.disabled = canSolve;
correctionTextPar.innerHTML = '&nbsp;';
updateView(currentFlashcard);
}
else {
throw Error('No flashcards loaded...');
}
}
function checkSolution() {
const solution = readSolution(currentFlashcard.flashcard.cardType);
if (solution === null) {
alert("Sie können keine leere Lösung abgeben!");
return;
}
const headers = new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Csrf-Token': document.querySelector('input[name="csrfToken"]').value
});
fetch(checkSolutionUrl, { method: 'PUT', body: JSON.stringify(solution), headers })
.then((response) => {
if (response.status === 200) {
return response.json()
.then(obj => onCorrectionSuccess(obj, currentFlashcard.flashcard.cardType));
}
else {
response.text().then(text => console.error(text));
return Promise.reject("Error code was " + response.status);
}
})
.catch(reason => {
console.error(reason);
});
}
function updateReadQuestionButton(readQuestionButton) {
const numOfFoundVoices = window.speechSynthesis.getVoices().length;
if (numOfFoundVoices > 0) {
console.info("Found " + numOfFoundVoices + " voices!");
readQuestionButton.classList.remove('hide');
readQuestionButton.disabled = false;
readQuestionButton.onclick = () => {
const toRead = currentFlashcard.frontToBack ? currentFlashcard.flashcard.fronts : currentFlashcard.flashcard.backs;
toRead.forEach((front) => {
const utterance = new SpeechSynthesisUtterance(front);
utterance.lang = 'fr';
window.speechSynthesis.speak(utterance);
});
};
}
else {
console.warn("Could not find any voices for Speech synthesis!");
}
}
domReady(() => {
const initialLoadBtn = document.querySelector('#loadFlashcardButton');
const loadFlashcardUrl = initialLoadBtn.dataset['href'];
initialLoadBtn.onclick = () => {
initialLoadNextFlashcards(loadFlashcardUrl);
initialLoadBtn.remove();
};
initialLoadBtn.click();
correctionTextPar = document.querySelector('#correctionTextPar');
const readQuestionButton = document.querySelector('#readQuestionButton');
updateReadQuestionButton(readQuestionButton);
window.speechSynthesis.onvoiceschanged = () => {
updateReadQuestionButton(readQuestionButton);
};
window.speechSynthesis.getVoices();
nextFlashcardBtn = document.querySelector('#nextFlashcardBtn');
nextFlashcardBtn.onclick = () => loadNextFlashcard();
checkSolutionBtn = document.querySelector('#checkSolutionBtn');
checkSolutionBtn.onclick = checkSolution;
checkSolutionUrl = checkSolutionBtn.dataset['href'];
maxNumOfCards = parseInt(document.querySelector('#maxCardCountSpan').innerText);
progressDiv = document.querySelector('#progressDiv');
document.addEventListener('keypress', event => {
if (event.key === 'Enter') {
if (event.ctrlKey) {
readQuestionButton.click();
}
else if (canSolve) {
checkSolutionBtn.click();
}
else {
nextFlashcardBtn.click();
}
}
else if (currentFlashcard.flashcard.cardType === 'Choice' && canSolve) {
const pressedKey = parseInt(event.key);
const choiceParagraph = document.querySelector('#answerDiv')
.querySelectorAll('p.choiceParagraph')
.item(pressedKey - 1);
if (choiceParagraph !== null) {
choiceParagraph.querySelector('input').click();
}
}
});
});
//# sourceMappingURL=/assets/learnRepeat.js.map
\ No newline at end of file
{"version":3,"file":"learnRepeat.js","sourceRoot":"/assets/","sources":["learnRepeat.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
......@@ -27,9 +27,9 @@ function readSolution(cardType: CardType): undefined | Solution {
const solutionInputs: HTMLInputElement[] = Array.from(document.querySelectorAll<HTMLInputElement>('.translation_input'));
solutions = solutionInputs
.map((input: HTMLInputElement) => {
.map((input: HTMLInputElement, index: number) => {
return {
id: -1,
id: index,
solution: input.value.trim()
};
})
......@@ -102,7 +102,7 @@ function onCorrectionSuccess(result: CorrectionResult, cardType: CardType): void
document.querySelector('#answeredFcCountSpan').innerHTML = answeredFlashcards.toString();
// FIXME: disable solution inputs?
if (currentFlashcard.flashcard.cardType === 'Text' || currentFlashcard.flashcard.cardType === 'Word') {
if (currentFlashcard.flashcard.cardType in ['Text', 'Word']) {
document.querySelectorAll<HTMLInputElement>('.translation_input').forEach(
(translationInput: HTMLInputElement) => translationInput.disabled = true
);
......@@ -121,6 +121,15 @@ function onCorrectionSuccess(result: CorrectionResult, cardType: CardType): void
switch (cardType) {
case 'Word':
case 'Text':
result.matchingResult.matches.forEach((match: Match) => {
const translationInput: HTMLInputElement = document.querySelector<HTMLInputElement>(`#translation_input_${match.start.id}`);
const isCorrect = match.distance === 0;
translationInput.classList.remove(isCorrect ? 'invalid' : 'valid');
translationInput.classList.add(isCorrect ? 'valid' : 'invalid');
});
break;
case 'Blank':
document.querySelectorAll<HTMLInputElement>('.translation_input').forEach((textInput) => {
textInput.classList.remove(result.correct ? 'invalid' : 'valid');
......@@ -281,4 +290,3 @@ domReady(() => {
}
});
});
function shuffleArray(array) {
let newArray = array.slice(0);
for (let i = newArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[newArray[i], newArray[j]] = [newArray[j], newArray[i]];
}
return newArray;
}
function domReady(callBack) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', callBack);
}
else {
callBack();
}
}
//# sourceMappingURL=/assets/learnRepeatBasics.js.map
\ No newline at end of file
{"version":3,"file":"learnRepeatBasics.js","sourceRoot":"/assets/","sources":["learnRepeatBasics.ts"],"names":[],"mappings":"AAIA,SAAS,YAAY,CAAI,KAAU;IAC/B,IAAI,QAAQ,GAAQ,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;KAC3D;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC;AAED,SAAS,QAAQ,CAAC,QAAoB;IAClC,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE;QACnC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;KAC3D;SAAM;QACH,QAAQ,EAAE,CAAC;KACd;AACL,CAAC"}
\ No newline at end of file
......@@ -72,21 +72,22 @@ interface Solution {
}
interface EditOperation {
operationType: "Replace" | "Insert" | "Delete"
index: number
char: string | null
operationType: "Replace" | "Insert" | "Delete";
index: number;
char: string | null;
}
interface AnswerSelectionResult {
wrong: number[]
correct: number[]
missing: number[]
wrong: number[];
correct: number[];
missing: number[];
}
interface Match {
start: string;
start: StringSolution;
target: string;
distance: number;
editOperations: EditOperation[];
}
interface MatchingResult {
......@@ -95,9 +96,9 @@ interface MatchingResult {
}
interface CorrectionResult {
correct: boolean
correct: boolean;
matchingResult: MatchingResult;
answersSelection: AnswerSelectionResult
newTriesCount: number
maybeSampleSolution: string | null
answersSelection: AnswerSelectionResult;
newTriesCount: number;
maybeSampleSolution: string | null;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class LevenshteinDistance {
constructor(a, b, distance, editOps) {
this.a = a;
this.b = b;
this.distance = distance;
this.editOps = editOps;
}
}
exports.LevenshteinDistance = LevenshteinDistance;
function levenshtein(a, b) {
const an = a ? a.length : 0;
const bn = b ? b.length : 0;
if (an === 0) {
return new LevenshteinDistance(a, b, bn, []);
}
if (bn === 0) {
return new LevenshteinDistance(a, b, an, []);
}
const matrix = new Array(bn + 1);
for (let i = 0; i <= bn; ++i) {
let row = matrix[i] = new Array(an + 1);
row[0] = i;
}
const firstRow = matrix[0];
for (let j = 1; j <= an; ++j) {
firstRow[j] = j;
}
for (let i = 1; i <= bn; ++i) {
for (let j = 1; j <= an; ++j) {
if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
}
else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1], matrix[i][j - 1], matrix[i - 1][j]) + 1;
}
}
}
return new LevenshteinDistance(a, b, matrix[bn][an], levenshteinBacktrace(a, b, matrix, an, bn));
}
exports.levenshtein = levenshtein;
function levenshteinBacktrace(a, b, matrix, an, bn) {
if (an > 0 && matrix[an - 1][bn] + 1 == matrix[an][bn]) {
return levenshteinBacktrace(a, b, matrix, an - 1, bn).concat({ operationType: 'Delete', char: a[an], index: an });
}
else if (bn > 0 && matrix[an][bn - 1] == matrix[an][bn]) {
return levenshteinBacktrace(a, b, matrix, an, bn - 1);
}
else if (an > 0 && bn > 0 && matrix[an - 1][bn - 1] + 1 == matrix[an][bn]) {
return levenshteinBacktrace(a, b, matrix, an - 1, bn - 1);
}
else if (an > 0 && bn > 0 && matrix[an - 1][bn - 1] == matrix[an][bn]) {
return levenshteinBacktrace(a, b, matrix, an - 1, bn - 1);
}
else {
return [];
}
}
//# sourceMappingURL=/assets/levenshtein.js.map
\ No newline at end of file
{"version":3,"file":"levenshtein.js","sourceRoot":"/assets/","sources":["levenshtein.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment