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

Zwischencommit

parent 53ec00f6
......@@ -18,7 +18,7 @@ let maxNumOfCards: number = 10;
let answeredFlashcards: number = 0;
function readSolution(cardType: CardType): undefined | Solution {
let solutions: string[] = [];
let solutions: StringSolution[] = [];
let selectedAnswers: number[] = [];
switch (cardType) {
......@@ -27,8 +27,13 @@ function readSolution(cardType: CardType): undefined | Solution {
const solutionInputs: HTMLInputElement[] = Array.from(document.querySelectorAll<HTMLInputElement>('.translation_input'));
solutions = solutionInputs
.map((input) => input.value.trim())
.filter((str) => str.length !== 0);
.map((input: HTMLInputElement) => {
return {
id: -1,
solution: input.value.trim()
};
})
.filter((solution: StringSolution) => solution.solution.length !== 0);
if (solutions.length === 0) {
alert('Sie können keine leere Lösung abgeben!');
......@@ -98,7 +103,9 @@ function onCorrectionSuccess(result: CorrectionResult, cardType: CardType): void
// FIXME: disable solution inputs?
if (currentFlashcard.flashcard.cardType === 'Text' || currentFlashcard.flashcard.cardType === 'Word') {
document.querySelector<HTMLInputElement>('#translation_input').disabled = true;
document.querySelectorAll<HTMLInputElement>('.translation_input').forEach(
(translationInput: HTMLInputElement) => translationInput.disabled = true
);
}
if (answeredFlashcards >= maxNumOfCards) {
......@@ -115,9 +122,10 @@ function onCorrectionSuccess(result: CorrectionResult, cardType: CardType): void
case 'Word':
case 'Text':
case 'Blank':
const textInput = document.querySelector<HTMLInputElement>('#translation_input');
textInput.classList.remove(result.correct ? 'invalid' : 'valid');
textInput.classList.add(result.correct ? 'valid' : 'invalid');
document.querySelectorAll<HTMLInputElement>('.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));
......
......@@ -56,12 +56,17 @@ interface FlashcardToAnswer {
currentBucket: undefined | number;
}
interface StringSolution {
id: number;
solution: string;
}
interface Solution {
cardId: number;
collId: number;
courseId: number;
solutions: string[];
solutions: StringSolution[];
selectedAnswers: number[];
frontToBack: boolean;
}
......@@ -78,9 +83,20 @@ interface AnswerSelectionResult {
missing: number[]
}
interface Match {
start: string;
target: string;
distance: number;
}
interface MatchingResult {
matches: Match[];
nonMatchedSamples: string[];
}
interface CorrectionResult {
correct: boolean
operations: EditOperation[]
matchingResult: MatchingResult;
answersSelection: AnswerSelectionResult
newTriesCount: number
maybeSampleSolution: string | null
......
......@@ -6,7 +6,7 @@ function buildTextAnswerInput(answers: string[]): string {
<div class="input-field col s12">
<input type="text" class="translation_input"
id="translation_input_${index}" data-index="${index}"
autofocus autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
<label for="translation_input_${index}">Übersetzung ${index + 1}</label>
</div>
</div>`.trim()
......
......@@ -51,7 +51,7 @@ class ApiController @Inject()(cc: ControllerComponents, protected val tableDefs:
val (corrResult, newAnswer) = Corrector.completeCorrect(user, solution, flashcard, maybePreviousAnswer)
tableDefs.futureInsertOrUpdateUserAnswer(newAnswer).map { _ =>
Ok(JsonFormats.completeCorrectionResultFormat.writes(corrResult))
Ok(JsonFormats.completeCorrectionResultWrites.writes(corrResult))
}
}
......
......@@ -2,18 +2,20 @@ package model
import model.levenshtein.EditOperation
final case class StringSolution(id: Int, solution: String)
final case class Solution(
cardId: Int,
collId: Int,
courseId: Int,
solutions: Seq[String],
solutions: Seq[StringSolution],
selectedAnswers: Seq[Int],
frontToBack: Boolean
)
final case class CorrectionResult(
correct: Boolean,
operations: Seq[EditOperation] = Seq.empty,
// operations: Seq[EditOperation] = Seq.empty,
matchingResult: Option[MatchingResult] = None,
answersSelection: Option[AnswerSelectionResult] = None,
newTriesCount: Int = 0,
......
package model
import model.Consts.frontBackSplitChar
import java.time.LocalDate
object Corrector {
......@@ -82,11 +83,9 @@ object Corrector {
val maybeSampleSolution = if (newWrongTriesCount < 2) {
None
} else if (solution.frontToBack) {
// FIXME: do not use head!
Some(flashcard.backs.head)
Some(flashcard.backs.mkString(frontBackSplitChar))
} else {
// FIXME: do not use head!
Some(flashcard.fronts.head)
Some(flashcard.fronts.mkString(frontBackSplitChar))
}
(
......
......@@ -2,13 +2,19 @@ package model
import model.levenshtein._
import play.api.libs.json._
import play.api.libs.functional.syntax._
object JsonFormats {
// Incoming
val solutionFormat: Format[Solution] = Json.format[Solution]
private val stringSolutionFormat: Format[StringSolution] = Json.format[StringSolution]
val solutionFormat: Format[Solution] = {
implicit val ssf: Format[StringSolution] = stringSolutionFormat
Json.format[Solution]
}
// Result
......@@ -27,14 +33,32 @@ object JsonFormats {
Json.format[EditOperation]
}
private val answerSelectionResultFormat: Format[AnswerSelectionResult] = Json.format[AnswerSelectionResult]
private val levenshteinDistanceWrites: Writes[LevenshteinDistance] = {
def unapplyLevenshteinDistance: LevenshteinDistance => (String, String, Int) = ld => (ld.start, ld.target, ld.distance)
(
(__ \ "start").write[String] and
(__ \ "target").write[String] and
(__ \ "distance").write[Int]
) (unapplyLevenshteinDistance)
}
val completeCorrectionResultFormat: Format[CorrectionResult] = {
private val matchingResultWrites: Writes[MatchingResult] = {
implicit val eof: Format[EditOperation] = editOperationFormat
implicit val ldf: Writes[LevenshteinDistance] = levenshteinDistanceWrites
Json.writes[MatchingResult]
}
private val answerSelectionResultFormat: Format[AnswerSelectionResult] = Json.format[AnswerSelectionResult]
val completeCorrectionResultWrites: Writes[CorrectionResult] = {
implicit val asrf: Format[AnswerSelectionResult] = answerSelectionResultFormat
Json.format[CorrectionResult]
implicit val mrf: Writes[MatchingResult] = matchingResultWrites
Json.writes[CorrectionResult]
}
// FlashcardToAnswer
......
......@@ -20,45 +20,45 @@ object Matcher {
distanceToBest: LevenshteinDistance
)
def doMatch(learnerSolutions: List[String], sampleSolutions: List[String]): MatchingResult = {
def doMatch(learnerSolutions: List[StringSolution], sampleSolutions: List[String]): MatchingResult = {
def matchHead(learnerSolution: String, sampleSolutions: List[String]): MatchHeadResult = {
def matchHead(learnerSol: StringSolution, sampleSolutions: List[String]): MatchHeadResult = {
@annotation.tailrec
def go(
learnerSolution: String,
remainingSamples: List[String],
learnerSolution: StringSolution,
remainingSampleSols: List[String],
priorSamples: List[String],
maybeBestAndDistanceToBest: Option[BestAndDistanceToBest],
posterior: List[String]
): MatchHeadResult = sampleSolutions match {
case Nil => MatchHeadResult(priorSamples ++ posterior, maybeBestAndDistanceToBest)
posteriorSamples: List[String]
): MatchHeadResult = remainingSampleSols match {
case Nil => MatchHeadResult(priorSamples ++ posteriorSamples, maybeBestAndDistanceToBest)
case head :: tail =>
val distanceToHead = LevenshteinDistance(learnerSolution, head)
val distanceToHead = LevenshteinDistance(learnerSolution.solution, head)
maybeBestAndDistanceToBest match {
case None =>
go(learnerSolution, tail, priorSamples ++ posterior, Some(BestAndDistanceToBest(head, distanceToHead)), List.empty[String])
go(learnerSolution, tail, priorSamples ++ posteriorSamples, Some(BestAndDistanceToBest(head, distanceToHead)), List.empty[String])
case Some(bestAndDistanceToBest) =>
if (distanceToHead.distance < bestAndDistanceToBest.distanceToBest.distance) {
go(learnerSolution, tail, priorSamples ++ (bestAndDistanceToBest.best :: posterior), Some(BestAndDistanceToBest(head, distanceToHead)), List.empty[String])
go(learnerSolution, tail, priorSamples ++ (bestAndDistanceToBest.best :: posteriorSamples), Some(BestAndDistanceToBest(head, distanceToHead)), List.empty[String])
} else {
go(learnerSolution, tail, priorSamples, maybeBestAndDistanceToBest, posterior :+ head)
go(learnerSolution, tail, priorSamples, maybeBestAndDistanceToBest, posteriorSamples :+ head)
}
}
}
go(learnerSolution, sampleSolutions, List.empty[String], None, List.empty[String])
go(learnerSol, sampleSolutions, List.empty[String], None, List.empty[String])
}
@annotation.tailrec
def go(learnerSolutions: List[String], sampleSolutions: List[String], matches: Seq[LevenshteinDistance]): MatchingResult = learnerSolutions match {
case Nil => MatchingResult(matches, sampleSolutions)
def go(learnerSols: List[StringSolution], sampleSols: List[String], matches: Seq[LevenshteinDistance]): MatchingResult = learnerSols match {
case Nil => MatchingResult(matches, sampleSols)
case head :: tail =>
matchHead(head, sampleSolutions) match {
matchHead(head, sampleSols) match {
case MatchHeadResult(remainingSamples, None) =>
// FIXME: sampleSolutions was empty ?!?
???
......
......@@ -27,7 +27,7 @@
<hr>
@helper.form(routes.LoginController.changePw, 'onsubmit -> "return checkPasswords();") {
@helper.form(routes.LoginController.changePw, Symbol("onsubmit") -> "return checkPasswords();") {
@helper.CSRF.formField
......
......@@ -10,7 +10,7 @@
<h2 class="center-align">@title</h2>
<form action="@routes.LoginController.login" method="post" class="col s12">
@helper.form(routes.LoginController.login, Symbol("class") -> "col s12") {
@helper.CSRF.formField
......@@ -22,5 +22,5 @@
<button class="btn btn-large waves-effect waves-light @accentColor">Login</button>
</div>
</form>
}
}
......@@ -10,7 +10,7 @@
<h2 class="center-align">@title</h2>
@helper.form(routes.LoginController.register(), 'class -> "col s12") {
@helper.form(routes.LoginController.register(), Symbol("class") -> "col s12") {
@helper.CSRF.formField
......
......@@ -12,7 +12,7 @@
<div class="row">
<div class="col s12">
@helper.form(routes.AdminController.uploadCardsFile(courseId, collectionId), 'enctype -> "multipart/form-data") {
@helper.form(routes.AdminController.uploadCardsFile(courseId, collectionId), Symbol("enctype") -> "multipart/form-data") {
@helper.CSRF.formField
......
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