Skip to content

Commit

Permalink
Implement quiz descriptions with markdown functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
krishnans2006 committed Jun 5, 2024
1 parent a21d8c9 commit d764587
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 12 deletions.
15 changes: 14 additions & 1 deletion tin/apps/assignments/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class Meta:
"is_quiz",
"quiz_action",
"quiz_autocomplete_enabled",
"quiz_description",
"quiz_description_markdown",
]
labels = {
"markdown": "Use markdown?",
Expand All @@ -84,6 +86,7 @@ class Meta:
"submission_limit_cooldown": "Rate limit cooldown period (minutes)",
"is_quiz": "Is this a quiz?",
"quiz_autocomplete_enabled": "Enable code autocompletion?",
"quiz_description_markdown": "Use markdown?",
}
sections = (
{
Expand Down Expand Up @@ -115,6 +118,8 @@ class Meta:
"is_quiz",
"quiz_action",
"quiz_autocomplete_enabled",
"quiz_description",
"quiz_description_markdown",
),
"collapsed": False,
},
Expand Down Expand Up @@ -159,8 +164,16 @@ class Meta:
"quiz_autocomplete_enabled": "This gives students basic code completion in the quiz editor, including "
"variable names, built-in functions, and keywords. It's recommended for quizzes that focus on code logic "
"and not syntax.",
"quiz_description": "Unlike the assignment description (left) which shows up on the assignment page, the "
"quiz description only appears once the student has started the quiz. This is useful for quiz "
"instructions that need to be hidden until the student enters the monitored quiz environment.",
"quiz_description_markdown": "This allows adding images, code blocks, or hyperlinks to the quiz "
"description.",
}
widgets = {
"description": forms.Textarea(attrs={"cols": 30, "rows": 8}),
"quiz_description": forms.Textarea(attrs={"cols": 30, "rows": 6}),
}
widgets = {"description": forms.Textarea(attrs={"cols": 30, "rows": 4})}

def __str__(self) -> str:
return f"AssignmentForm(\"{self['name'].value()}\")"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.13 on 2024-06-05 02:20

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("assignments", "0031_assignment_quiz_autocomplete_enabled"),
]

operations = [
migrations.AddField(
model_name="assignment",
name="quiz_description",
field=models.CharField(blank=True, default="", max_length=4096),
),
migrations.AddField(
model_name="assignment",
name="quiz_description_markdown",
field=models.BooleanField(default=False),
),
]
2 changes: 2 additions & 0 deletions tin/apps/assignments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ class Assignment(models.Model):
QUIZ_ACTIONS = (("0", "Log only"), ("1", "Color Change"), ("2", "Lock"))
quiz_action = models.CharField(max_length=1, choices=QUIZ_ACTIONS, default="2")
quiz_autocomplete_enabled = models.BooleanField(default=False)
quiz_description = models.CharField(max_length=4096, default="", null=False, blank=True)
quiz_description_markdown = models.BooleanField(default=False)

objects = AssignmentQuerySet.as_manager()

Expand Down
7 changes: 3 additions & 4 deletions tin/static/css/edit.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,11 @@ button.collapsible.active:after {

/* Style the description box */
textarea {
width: 90%;
height: 300px;
width: 95%;
resize: vertical;
/* For legacy browsers without CSS 3 support */
min-width: 90%;
max-width: 90%;
min-width: 95%;
max-width: 95%;
}

@media (max-width: 900.02px) {
Expand Down
77 changes: 70 additions & 7 deletions tin/static/js/markdown-image-dragdrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ $(function () {
position: 'relative',
});

const upload_overlay = $('<div>')
const uploadOverlay = $('<div>')
.css({
display: 'none',
position: 'absolute',
top: 0,
left: 0,
width: '92%',
width: '97%',
height: '100%',
'background-color': 'rgba(0, 0, 0, 0.2)',
'z-index': 1000,
'text-align': 'center',
border: '10px dashed #000',
padding: '100px 20px 0px 20px',
padding: '30px 20px 0px 20px',
'font-size': '250%',
'box-sizing': 'border-box',
})
Expand All @@ -57,7 +57,7 @@ $(function () {
if (markdownToggle.prop('checked')) {
const dt = e.originalEvent.dataTransfer;
if (dt.types.includes('Files')) {
upload_overlay.stop().fadeIn(150);
uploadOverlay.stop().fadeIn(150);
}
}
},
Expand Down Expand Up @@ -87,13 +87,76 @@ $(function () {
insertAtCursor(description[0], `![${name}](${url})`);
});
}
upload_overlay.stop().fadeOut(150);
uploadOverlay.stop().fadeOut(150);
}
},
});

upload_overlay.on('dragleave', function () {
upload_overlay.stop().fadeOut(150);
uploadOverlay.on('dragleave', function () {
uploadOverlay.stop().fadeOut(150);
});

// This is basically a copy-paste of the above code, but for the quiz description
// I'm not sure how to refactor this to completely avoid code duplication, but I've made an attempt
const quizMarkdownToggle = $('#id_quiz_description_markdown');
const quizDescription = $('#id_quiz_description');
const quizDescriptionParent = quizDescription.parent();

quizDescriptionParent.css({
position: 'relative',
});

const quizUploadOverlay = uploadOverlay
.clone()
.appendTo(quizDescriptionParent);

quizDescriptionParent.on({
dragover: function (e) {
if (quizMarkdownToggle.prop('checked')) {
e.preventDefault();
}
},
dragenter: function (e) {
if (quizMarkdownToggle.prop('checked')) {
const dt = e.originalEvent.dataTransfer;
if (dt.types.includes('Files')) {
quizUploadOverlay.stop().fadeIn(150);
}
}
},
drop: function (e) {
if (quizMarkdownToggle.prop('checked')) {
const dt = e.originalEvent.dataTransfer;
e.preventDefault();
if (dt && dt.files.length) {
if (dt.files.length != 1) {
alert('Please only upload one file at a time.');
return;
}

let data = new FormData();
data.append('key', IMGBB_API_KEY);
data.append('image', dt.files[0]);

$.ajax({
url: 'https://api.imgbb.com/1/upload',
method: 'POST',
data: data,
processData: false,
contentType: false,
}).done(function (data) {
const name = data.data.title;
const url = data.data.url;
insertAtCursor(quizDescription[0], `![${name}](${url})`);
});
}
quizUploadOverlay.stop().fadeOut(150);
}
},
});

quizUploadOverlay.on('dragleave', function () {
quizUploadOverlay.stop().fadeOut(150);
});
}
});
10 changes: 10 additions & 0 deletions tin/templates/assignments/quiz.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% extends "base_wo_head.html" %}
{% load static %}
{% load markdownify %}

{% block title %}
Turn-In: {{ assignment.name }}: Take Quiz
Expand Down Expand Up @@ -132,6 +133,15 @@ <h2>{{ assignment.name }}: Take Quiz</h2>

{% if assignment.grader_file %}

{% if assignment.quiz_description %}
{% if assignment.quiz_description_markdown %}
{{ assignment.quiz_description | markdownify }}
{% else %}
<p>{{ assignment.quiz_description | linebreaks }}</p>
{% endif %}
{% endif %}


{% if latest_submission %}
<h3 style="border-top:1px solid lightgray;padding-top:15px;">Grader output</h3>
<div id="grader-output" class="code-result{% if not latest_submission.complete %} incomplete{% endif %}"
Expand Down

0 comments on commit d764587

Please sign in to comment.