have basic quiz editor implemented

This commit is contained in:
2023-10-10 17:16:08 -06:00
parent 008b85b971
commit e5defbc0cf
8 changed files with 231 additions and 16 deletions

View File

@@ -35,7 +35,7 @@ this is my description in markdown
markdown.Should().Contain("LockAtDueDate: true"); markdown.Should().Contain("LockAtDueDate: true");
markdown.Should().Contain("ShuffleAnswers: true"); markdown.Should().Contain("ShuffleAnswers: true");
markdown.Should().Contain("OneQuestionAtATime: false"); markdown.Should().Contain("OneQuestionAtATime: false");
markdown.Should().Contain("LocalAssignmentGroupName: someId"); markdown.Should().Contain("AssignmentGroup: someId");
markdown.Should().Contain("AllowedAttempts: -1"); markdown.Should().Contain("AllowedAttempts: -1");
} }
[Test] [Test]
@@ -70,8 +70,8 @@ lines
QuestionType = QuestionType.MULTIPLE_CHOICE, QuestionType = QuestionType.MULTIPLE_CHOICE,
Answers = new LocalQuizQuestionAnswer[] Answers = new LocalQuizQuestionAnswer[]
{ {
new LocalQuizQuestionAnswer() { Id = "asdfa", Correct = true, Text = "true" }, new LocalQuizQuestionAnswer() { Correct = true, Text = "true" },
new LocalQuizQuestionAnswer() { Id = "wef", Correct = false, Text = "false" + Environment.NewLine +Environment.NewLine + "endline" }, new LocalQuizQuestionAnswer() { Correct = false, Text = "false" + Environment.NewLine +Environment.NewLine + "endline" },
} }
} }
} }
@@ -120,9 +120,9 @@ b) false
QuestionType = QuestionType.MULTIPLE_ANSWERS, QuestionType = QuestionType.MULTIPLE_ANSWERS,
Answers = new LocalQuizQuestionAnswer[] Answers = new LocalQuizQuestionAnswer[]
{ {
new LocalQuizQuestionAnswer() { Id = "asdfsa", Correct = true, Text = "true" }, new LocalQuizQuestionAnswer() { Correct = true, Text = "true" },
new LocalQuizQuestionAnswer() { Id = "wsef", Correct = true, Text = "false"}, new LocalQuizQuestionAnswer() { Correct = true, Text = "false"},
new LocalQuizQuestionAnswer() { Id = "ws5ef", Correct = false, Text = "neither"}, new LocalQuizQuestionAnswer() { Correct = false, Text = "neither"},
} }
} }
} }

View File

@@ -0,0 +1,45 @@
@using Markdig
@code {
[Parameter, EditorRequired]
public LocalQuizQuestion Question { get; set; } = default!;
}
@((MarkupString)Question.HtmlText)
@foreach(var answer in Question.Answers)
{
<div class="mx-3 mb-1 bg-dark px-2 rounded rounded-2 d-flex flex-row border">
<div>
@if(answer.Correct)
{
<svg
style="width: 1em;"
class="me-1"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M4 12.6111L8.92308 17.5L20 6.5"
stroke="var(--bs-success)"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
}
else
{
<div
class="me-1"
style="width: 1em;"
></div>
}
</div>
<div>
@((MarkupString)answer.HtmlText)
</div>
</div>
}

View File

@@ -0,0 +1,121 @@
@using Management.Web.Shared.Components
@inject QuizEditorContext quizContext
@code {
private Modal? modal { get; set; }
private LocalQuiz testQuiz;
private string? error { get; set; } = null;
private string _quizMarkdownInput { get; set; } = "";
private string quizMarkdownInput
{
get => _quizMarkdownInput;
set
{
_quizMarkdownInput = value;
try
{
var newQuiz = LocalQuiz.ParseMarkdown(_quizMarkdownInput);
error = null;
testQuiz = newQuiz;
}
catch(Exception e)
{
error = e.Message;
}
}
}
protected override void OnInitialized()
{
quizContext.StateHasChanged += reload;
}
private void reload()
{
if (quizContext.Quiz != null)
{
Console.WriteLine("reloading quiz editor");
if(quizMarkdownInput == "")
{
quizMarkdownInput = quizContext.Quiz.ToMarkdown();
}
modal?.Show();
this.InvokeAsync(this.StateHasChanged);
}
}
public void Dispose()
{
quizContext.StateHasChanged -= reload;
}
private void deleteQuiz()
{
quizContext.DeleteQuiz();
modal?.Hide();
}
private async Task addToCanvas()
{
await quizContext.AddQuizToCanvas();
}
private void onHide()
{
quizMarkdownInput = "";
quizContext.Quiz = null;
}
}
<Modal @ref="modal" OnHide="onHide" >
<Title>
<div class="row justify-content-between">
<div class="col-auto">
@quizContext.Quiz?.Name
</div>
<div class="col-auto me-3">
Points: @quizContext.Quiz?.Questions.Sum(q => q.Points)
</div>
</div>
</Title>
<Body>
<div class="row">
<div class="col-6">
<textarea
rows="30"
class="form-control"
@bind="quizMarkdownInput"
@bind:event="oninput"
/>
</div>
<div class="col-6">
@if(error != null)
{
<p class="text-danger">@error</p>
}
<QuizPreview Quiz="testQuiz" />
</div>
</div>
</Body>
<Footer>
<ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirm="deleteQuiz" />
<button
class="btn btn-outline-secondary"
@onclick="addToCanvas"
>
Add to Canvas
</button>
<button
class="btn btn-primary"
@onclick="() => modal?.Hide()"
>
Done
</button>
</Footer>
</Modal>

View File

@@ -0,0 +1,48 @@
@using Management.Web.Shared.Components
@inject QuizEditorContext quizContext
@code {
[Parameter, EditorRequired]
public LocalQuiz Quiz { get; set; } = default!;
protected override void OnInitialized()
{
quizContext.StateHasChanged += reload;
}
private void reload()
{
Console.WriteLine(JsonSerializer.Serialize(quizContext.Quiz));
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
quizContext.StateHasChanged -= reload;
}
}
@if(Quiz != null)
{
<div>Name: @Quiz.Name</div>
<div>Due At: @Quiz.DueAt</div>
<div>Lock At: @Quiz.LockAt</div>
<div>Shuffle Answers: @Quiz.ShuffleAnswers</div>
<div>Allowed Attempts: @Quiz.AllowedAttempts</div>
<div>One question at a time: @Quiz.OneQuestionAtATime</div>
<div>Assignment Group: @Quiz.LocalAssignmentGroupName</div>
<div class="p-3">@Quiz.Description</div>
@foreach(var question in Quiz.Questions)
{
<div class="bg-dark-subtle mt-1 p-1 rounded rounded-2">
<MarkdownQuestionPreview
Question="question"
@key="question"
/>
</div>
}
}

View File

@@ -4,6 +4,7 @@
@using Management.Web.Shared.Semester @using Management.Web.Shared.Semester
@using Management.Web.Shared.Components.AssignmentForm @using Management.Web.Shared.Components.AssignmentForm
@using Management.Web.Shared.Components.Quiz @using Management.Web.Shared.Components.Quiz
@using Management.Web.Shared.Components.Quiz.Markdown
@inject CanvasService canvas @inject CanvasService canvas
@inject CoursePlanner planner @inject CoursePlanner planner
@@ -40,7 +41,8 @@
} }
} }
<QuizForm /> <MarkdownQuizForm />
@* <QuizForm /> *@
<div class="row"> <div class="row">
<div class="col overflow-y-auto border rounded " style="max-height: 95vh;"> <div class="col overflow-y-auto border rounded " style="max-height: 95vh;">

View File

@@ -49,7 +49,7 @@ LockAt: {LockAt}
DueAt: {DueAt} DueAt: {DueAt}
ShuffleAnswers: {ShuffleAnswers.ToString().ToLower()} ShuffleAnswers: {ShuffleAnswers.ToString().ToLower()}
OneQuestionAtATime: {OneQuestionAtATime.ToString().ToLower()} OneQuestionAtATime: {OneQuestionAtATime.ToString().ToLower()}
LocalAssignmentGroupName: {LocalAssignmentGroupName} AssignmentGroup: {LocalAssignmentGroupName}
AllowedAttempts: {AllowedAttempts} AllowedAttempts: {AllowedAttempts}
Description: {Description} Description: {Description}
--- ---
@@ -84,8 +84,8 @@ Description: {Description}
var dueAt = DateTime.Parse(extractLabelValue(settings, "DueAt")); var dueAt = DateTime.Parse(extractLabelValue(settings, "DueAt"));
var lockAt = DateTime.Parse(extractLabelValue(settings, "LockAt")); var lockAt = DateTime.Parse(extractLabelValue(settings, "LockAt"));
var description = extractDescription(settings); var description = extractDescription(settings);
var assignmentGroup = extractLabelValue(settings, "AssignmentGroup");
// var assignmentGroup = ExtractLabelValue(settings, "AssignmentGroup");
return new LocalQuiz() return new LocalQuiz()
{ {
Id = "id-" + name, Id = "id-" + name,
@@ -96,7 +96,7 @@ Description: {Description}
DueAt = dueAt, DueAt = dueAt,
ShuffleAnswers = shuffleAnswers, ShuffleAnswers = shuffleAnswers,
OneQuestionAtATime = oneQuestionAtATime, OneQuestionAtATime = oneQuestionAtATime,
// LocalAssignmentGroupId = "someId", LocalAssignmentGroupName = assignmentGroup,
AllowedAttempts = allowedAttempts, AllowedAttempts = allowedAttempts,
Questions = new LocalQuizQuestion[] { } Questions = new LocalQuizQuestion[] { }
}; };

View File

@@ -13,7 +13,7 @@ public record LocalQuizQuestionAnswer
public static LocalQuizQuestionAnswer ParseMarkdown(string input) public static LocalQuizQuestionAnswer ParseMarkdown(string input)
{ {
var isCorrect = input[0] == '*' || input[1] == '*'; var isCorrect = input[0] == '*' || input[1] == '*';
string startingQuestionPattern = @"^(?:\*[a-z]\))|\[\s*\]|\[\*\] "; string startingQuestionPattern = @"^(\*?[a-z]\))|\[\s*\]|\[\*\] ";
var text = Regex.Replace(input, startingQuestionPattern, string.Empty).Trim(); var text = Regex.Replace(input, startingQuestionPattern, string.Empty).Trim();
return new LocalQuizQuestionAnswer() return new LocalQuizQuestionAnswer()
@@ -22,5 +22,4 @@ public record LocalQuizQuestionAnswer
Text=text, Text=text,
}; };
} }
} }