feat: quiz redesign
This commit is contained in:
@@ -184,7 +184,8 @@ jinja = {
|
|||||||
"school.lms.utils.is_eligible_to_review",
|
"school.lms.utils.is_eligible_to_review",
|
||||||
"school.lms.utils.get_initial_members",
|
"school.lms.utils.get_initial_members",
|
||||||
"school.lms.utils.get_sorted_reviews",
|
"school.lms.utils.get_sorted_reviews",
|
||||||
"school.lms.utils.is_instructor"
|
"school.lms.utils.is_instructor",
|
||||||
|
"school.lms.utils.convert_number_to_character"
|
||||||
],
|
],
|
||||||
"filters": []
|
"filters": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import re
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import flt, cint, cstr
|
from frappe.utils import flt, cint, cstr
|
||||||
from school.lms.md import markdown_to_html
|
from school.lms.md import markdown_to_html
|
||||||
|
import string
|
||||||
|
|
||||||
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
|
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
|
||||||
|
|
||||||
@@ -292,3 +293,6 @@ def get_initial_members(course):
|
|||||||
|
|
||||||
def is_instructor(course):
|
def is_instructor(course):
|
||||||
return len(list(filter(lambda x: x.name == frappe.session.user, get_instructors(course)))) > 0
|
return len(list(filter(lambda x: x.name == frappe.session.user, get_instructors(course)))) > 0
|
||||||
|
|
||||||
|
def convert_number_to_character(number):
|
||||||
|
return string.ascii_uppercase[number]
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a class="button-links" href="{{get_profile_url(review.owner_details.username) }}">
|
<a class="button-links" href="{{get_profile_url(review.owner_details.username) }}">
|
||||||
<span class="review-author">
|
<span class="bold-heading">
|
||||||
{{ review.owner_details.full_name }}
|
{{ review.owner_details.full_name }}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -308,11 +308,6 @@ input[type=checkbox] {
|
|||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-checkbox {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-checkbox>label>input {
|
.custom-checkbox>label>input {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
@@ -324,6 +319,10 @@ input[type=checkbox] {
|
|||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-checkbox {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.custom-checkbox>label>input:checked+.empty-checkbox {
|
.custom-checkbox>label>input:checked+.empty-checkbox {
|
||||||
background: url(/assets/school/icons/tick.svg);
|
background: url(/assets/school/icons/tick.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@@ -331,6 +330,8 @@ input[type=checkbox] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.quiz-label {
|
.quiz-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@@ -827,8 +828,7 @@ input[type=checkbox] {
|
|||||||
|
|
||||||
.question {
|
.question {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 85%;
|
padding: 1.25rem;
|
||||||
margin: 0 auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.question p {
|
.question p {
|
||||||
@@ -887,6 +887,7 @@ input[type=checkbox] {
|
|||||||
.lesson-pagination {
|
.lesson-pagination {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
margin: 24px 0px 0px;
|
margin: 24px 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1683,7 +1684,7 @@ pre {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-author {
|
.bold-heading {
|
||||||
font-size: var(--text-lg);
|
font-size: var(--text-lg);
|
||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -1715,3 +1716,35 @@ pre {
|
|||||||
.reviews-parent .progress-bar {
|
.reviews-parent .progress-bar {
|
||||||
background-color: var(--gray-600);
|
background-color: var(--gray-600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.question-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-number {
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
padding: 0.75rem;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-option .option-text {
|
||||||
|
background-color: var(--blue-50);
|
||||||
|
border: 1px solid var(--blue-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.question-text {
|
||||||
|
font-size: var(--text-lg);
|
||||||
|
color: var(--gray-900);
|
||||||
|
font-weight: 600;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,34 +2,34 @@
|
|||||||
|
|
||||||
<div class="card-divider"></div>
|
<div class="card-divider"></div>
|
||||||
|
|
||||||
<div class="mt-5">
|
<div class="">
|
||||||
<form id="quiz-form">
|
<form id="quiz-form">
|
||||||
<div class="questions">
|
<div class="questions">
|
||||||
{% for question in quiz.questions %}
|
{% for question in quiz.questions %}
|
||||||
<div class="question {% if loop.index == 1 %} active-question {% else %} hide {% endif %}"
|
{% set instruction = _("Choose all answers that apply") if question.multiple else _("Choose 1 answer") %}
|
||||||
|
<div class="question common-card-style {% if loop.index == 1 %} active-question {% else %} hide {% endif %}"
|
||||||
data-question="{{ question.question }}" data-multi="{{ question.multiple}}" data-qt-index="{{ loop.index }}">
|
data-question="{{ question.question }}" data-multi="{{ question.multiple}}" data-qt-index="{{ loop.index }}">
|
||||||
<p>{{ frappe.utils.md_to_html(question.question) }}</p>
|
<div class="question-header">
|
||||||
|
<div class="question-number">{{ loop.index }}</div>
|
||||||
|
<div class="question-text">
|
||||||
|
<div class="course-meta pull-right ml-2"> {{ instruction }} </div>
|
||||||
|
{{ frappe.utils.md_to_html(question.question) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if question.multiple %}
|
|
||||||
<small class="font-weight-bold">Choose all answers that apply:</small>
|
|
||||||
{% else %}
|
|
||||||
<small class="font-weight-bold">Choose 1 answer:</small>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="card-divider"></div>
|
|
||||||
|
|
||||||
{% set options = [question.option_1, question.option_2, question.option_3, question.option_4] %}
|
{% set options = [question.option_1, question.option_2, question.option_3, question.option_4] %}
|
||||||
|
|
||||||
{% for option in options %}
|
{% for option in options %}
|
||||||
{% if option %}
|
{% if option %}
|
||||||
|
|
||||||
<div class="custom-checkbox">
|
<div class="custom-checkbox">
|
||||||
<label class="quiz-label">
|
<label class="quiz-label">
|
||||||
|
<div class="course-meta font-weight-bold"> {{ convert_number_to_character(loop.index - 1) }}</div>
|
||||||
<input class="option" value="{{ option | urlencode }}"
|
<input class="option" value="{{ option | urlencode }}"
|
||||||
data-correct="{{ question['is_correct_' + loop.index | string] }}" {% if question.multiple %}
|
data-correct="{{ question['is_correct_' + loop.index | string] }}" {% if question.multiple %}
|
||||||
type="checkbox" {% else %} type="radio" name="{{ question.question | urlencode }}" {% endif %}>
|
type="checkbox" {% else %} type="radio" name="{{ question.question | urlencode }}" {% endif %}>
|
||||||
<img class="empty-checkbox mr-3" />
|
<div class="option-text">{{ frappe.utils.md_to_html(option) }}</div>
|
||||||
<span class="label-area">{{ frappe.utils.md_to_html(option) }}</span>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -38,7 +38,6 @@
|
|||||||
<small class="explanation muted-text hide">{{ explanation }}</small>
|
<small class="explanation muted-text hide">{{ explanation }}</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="card-divider"></div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
@@ -51,8 +50,8 @@
|
|||||||
<div class="button is-secondary hide" id="next">Next Question</div>
|
<div class="button is-secondary hide" id="next">Next Question</div>
|
||||||
<div class="button is-secondary is-default hide" id="summary">Summary</div>
|
<div class="button is-secondary is-default hide" id="summary">Summary</div>
|
||||||
<small id="submission-message" class="font-weight-bold hide"> Please join the course to submit the Quiz.</small>
|
<small id="submission-message" class="font-weight-bold hide"> Please join the course to submit the Quiz.</small>
|
||||||
|
<div class="button is-secondary hide" id="try-again">Try Again</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button is-secondary pull-right hide" id="try-again">Try Again</div>
|
|
||||||
<h4 class="success-message"></h4>
|
<h4 class="success-message"></h4>
|
||||||
<h5 class="score text-muted"></h5>
|
<h5 class="score text-muted"></h5>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ frappe.ready(() => {
|
|||||||
|
|
||||||
$(".clear-work").click((e) => {
|
$(".clear-work").click((e) => {
|
||||||
clear_work(e);
|
clear_work(e);
|
||||||
})
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,8 +57,10 @@ const save_current_lesson = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const enable_check = (e) => {
|
const enable_check = (e) => {
|
||||||
if ($(".option:checked").length && $("#check").attr("disabled")) {
|
if ($(".option:checked").length) {
|
||||||
$("#check").removeAttr("disabled");
|
$("#check").removeAttr("disabled");
|
||||||
|
$(".custom-checkbox").removeClass("active-option");
|
||||||
|
$(".option:checked").closest(".custom-checkbox").addClass("active-option");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,7 +166,7 @@ const quiz_summary = (e) => {
|
|||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
var message = data.message == total_questions ? "Excellent Work" : "You were almost there."
|
var message = data.message == total_questions ? "Excellent Work" : "You were almost there."
|
||||||
$(".question").addClass("hide");
|
$(".question").addClass("hide");
|
||||||
$(".quiz-footer").addClass("hide");
|
$("#summary").addClass("hide");
|
||||||
$("#quiz-form").parent().prepend(
|
$("#quiz-form").parent().prepend(
|
||||||
`<div class="text-center summary"><h2>${message} 👏 </h2>
|
`<div class="text-center summary"><h2>${message} 👏 </h2>
|
||||||
<div class="font-weight-bold">${data.message}/${total_questions} correct.</div></div>`);
|
<div class="font-weight-bold">${data.message}/${total_questions} correct.</div></div>`);
|
||||||
@@ -222,7 +224,7 @@ const parse_options = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const add_icon = (element, icon) => {
|
const add_icon = (element, icon) => {
|
||||||
var label = $(element).parent().find(".label-area p").text();
|
var label = $(element).siblings(".option-text").text();
|
||||||
$(element).parent().empty().html(`<img class="mr-3" src="/assets/school/icons/${icon}.svg"> ${label}`);
|
$(element).parent().empty().html(`<img class="mr-3" src="/assets/school/icons/${icon}.svg"> ${label}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -354,27 +356,27 @@ const clear_work = (e) => {
|
|||||||
parent.addClass("hide");
|
parent.addClass("hide");
|
||||||
parent.siblings(".attach-file").removeClass("hide").val(null);
|
parent.siblings(".attach-file").removeClass("hide").val(null);
|
||||||
parent.siblings(".submit-work").removeClass("hide");
|
parent.siblings(".submit-work").removeClass("hide");
|
||||||
}
|
};
|
||||||
|
|
||||||
const fetch_assignments = () => {
|
const fetch_assignments = () => {
|
||||||
if ($(".attach-file").length > 0) {
|
if ($(".attach-file").length <= 0)
|
||||||
frappe.call({
|
return;
|
||||||
method: "school.lms.doctype.lesson_assignment.lesson_assignment.get_assignment",
|
frappe.call({
|
||||||
args: {
|
method: "school.lms.doctype.lesson_assignment.lesson_assignment.get_assignment",
|
||||||
"lesson": $(".title").attr("data-lesson")
|
args: {
|
||||||
},
|
"lesson": $(".title").attr("data-lesson")
|
||||||
callback: (data) => {
|
},
|
||||||
if (data.message && data.message.length) {
|
callback: (data) => {
|
||||||
const assignments = data.message;
|
if (data.message && data.message.length) {
|
||||||
for (let i in assignments) {
|
const assignments = data.message;
|
||||||
let target = $(`#${assignments[i]["id"]}`);
|
for (let i in assignments) {
|
||||||
target.addClass("hide");
|
let target = $(`#${assignments[i]["id"]}`);
|
||||||
target.siblings(".submit-work").addClass("hide");
|
target.addClass("hide");
|
||||||
target.siblings(".preview-work").removeClass("hide");
|
target.siblings(".submit-work").addClass("hide");
|
||||||
target.siblings(".preview-work").find("a").attr("href", assignments[i]["assignment"]).text(assignments[i]["file_name"]);
|
target.siblings(".preview-work").removeClass("hide");
|
||||||
}
|
target.siblings(".preview-work").find("a").attr("href", assignments[i]["assignment"]).text(assignments[i]["file_name"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user