feat: quiz-creation-ui
This commit is contained in:
@@ -186,7 +186,7 @@
|
||||
<div class="mt-4">
|
||||
<button class="btn btn-primary btn-sm btn-lesson pull-right ml-2"> {{ _("Save") }} </button>
|
||||
<button class="btn btn-secondary btn-sm pull-right btn-back ml-2"> {{ _("Back to Lesson") }} </button>
|
||||
<a class="btn btn-secondary btn-sm pull-right" href="/courses/quiz-list"> {{ _("Create a Quiz") }} </a>
|
||||
<a class="btn btn-secondary btn-sm pull-right" href="/quizzes"> {{ _("Create a Quiz") }} </a>
|
||||
|
||||
<div class="attachments-parent">
|
||||
<div class="attachment-controls">
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% block title %}
|
||||
{{ _("Quiz List") }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block head_include %}
|
||||
{% include "public/icons/symbol-defs.svg" %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="common-page-style" style="background-color: var(--fg-color);">
|
||||
<div class="container">
|
||||
{{ BreadCrumb(quiz) }}
|
||||
{{ QuizCard(quiz) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% macro BreadCrumb(quiz) %}
|
||||
<div class="breadcrumb">
|
||||
<a class="dark-links" href="/courses">{{ _("Quizzes") }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<span class="breadcrumb-destination">{{ quiz.title if quiz.title else _("New Quiz") }}</span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro QuizCard(quiz) %}
|
||||
<div style="width: 60%;">
|
||||
|
||||
<div class="course-home-headings mb-2" data-placeholder="{{ _('Quiz Title') }}" id="quiz-title"
|
||||
contenteditable="true">{% if quiz.title %}{{ quiz.title }}{% endif %}</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button class="btn btn-secondary btn-sm btn-question"> {{ _("New Question") }} </button>
|
||||
<button class="btn btn-primary btn-sm btn-save-question ml-2 hide"> {{ _("Save") }} </button>
|
||||
</div>
|
||||
|
||||
|
||||
{% if quiz.question %}
|
||||
{% for question in quiz.questions %}
|
||||
<div class="quiz-card">
|
||||
<div contenteditable="true" data-placeholder="{{ _('Question') }}"
|
||||
class="mb-4">{% if question.question %} {{ question.question }} {% endif %}</div>
|
||||
|
||||
{% for num in range(1,5) %}
|
||||
{% set option = question["option_" + frappe.utils.cstr(num)] %}
|
||||
{% set explanation = question["explanation_" + frappe.utils.cstr(num)] %}
|
||||
|
||||
<div class="mt-4">
|
||||
<label class=""> {{ _("Option") }} {{ frappe.utils.cstr(num) }} </label>
|
||||
<div class="d-flex justify-content-between">
|
||||
<div contenteditable="true" data-placeholder="{{ _('Option') }}"
|
||||
class="option-input">{% if option %}{{ option }}{% endif %}</div>
|
||||
<div contenteditable="true" data-placeholder="{{ _('Explanation') }}"
|
||||
class="option-input">{% if explanation %}{{ explanation }}{% endif %}</div>
|
||||
<div class="option-checkbox">
|
||||
<input type="checkbox" {% if question['is_correct_' + frappe.utils.cstr(num)] %} checked {% endif %}>
|
||||
<label class="mb-0"> {{ _("Is Correct") }} </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
91
lms/www/batch/quiz.js
Normal file
91
lms/www/batch/quiz.js
Normal file
@@ -0,0 +1,91 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
$(".btn-question").click((e) => {
|
||||
add_question(e);
|
||||
});
|
||||
|
||||
$(".btn-save-question").click((e) => {
|
||||
save_question(e);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
const add_question = (e) => {
|
||||
let add_after = $(".quiz-card").length ? $(".quiz-card") : $("#quiz-title");
|
||||
let question_template = `<div class="quiz-card">
|
||||
<div contenteditable="true" data-placeholder="${__("Question")}" class="question mb-4"></div>
|
||||
</div>`;
|
||||
$(question_template).insertAfter(add_after);
|
||||
get_question_template();
|
||||
$(".btn-save-question").removeClass("hide");
|
||||
};
|
||||
|
||||
|
||||
const get_question_template = () => {
|
||||
Array.from({length: 4}, (x, num) => {
|
||||
let option_template = get_option_template(num + 1);
|
||||
let add_after = $(".quiz-card:last .option-group").length ? $(".quiz-card:last .option-group").last() : $(".question:last");
|
||||
question_template = $(option_template).insertAfter(add_after);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const get_option_template = (num) => {
|
||||
return `<div class="option-group mt-4">
|
||||
<label class="">${__("Option")} ${num}</label>
|
||||
<div class="d-flex justify-content-between option-${num}">
|
||||
<div contenteditable="true" data-placeholder="${ __("Option") }"
|
||||
class="option-input"></div>
|
||||
<div contenteditable="true" data-placeholder="${ __('Explanation') }"
|
||||
class="option-input"></div>
|
||||
<div class="option-checkbox">
|
||||
<input type="checkbox">
|
||||
<label class="mb-0"> ${ __("Is Correct") } </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
|
||||
const save_question = (e) => {
|
||||
if (!$("#quiz-title").text()) {
|
||||
frappe.throw(__("Quiz Title is mandatory."));
|
||||
}
|
||||
console.log(get_questions());
|
||||
debugger;
|
||||
frappe.call({
|
||||
method: lms.lms.doctype.lms_quiz.lms_quiz.save_quiz,
|
||||
args: {
|
||||
"quiz-title": $("#quiz-title"),
|
||||
"questions": get_questions()
|
||||
},
|
||||
callback: (data) => {
|
||||
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const get_questions = () => {
|
||||
let questions = [];
|
||||
|
||||
$(".quiz-card").each((i, elem) => {
|
||||
|
||||
if (!$(elem).find(".question").text())
|
||||
return;
|
||||
|
||||
let question_details = {};
|
||||
question_details["question"] = $(elem).find(".question").text();
|
||||
|
||||
Array.from({length: 4}, (x, i) => {
|
||||
let num = i + 1;
|
||||
question_details[`option_${num}`] = $(`.option-${num} .option-input:first`).text();
|
||||
question_details[`explanation_${num}`] = $(`.option-${num} .option-input:last`).text();
|
||||
question_details[`is_correct_${num}`] = $(`.option-${num} .option-checkbox`).find("input").prop("checked");
|
||||
});
|
||||
questions.push(question_details);
|
||||
});
|
||||
|
||||
return questions
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import frappe
|
||||
from frappe.utils import cstr
|
||||
|
||||
|
||||
def get_context(context):
|
||||
quizname = frappe.form_dict["quizname"]
|
||||
if quizname == "new-quiz":
|
||||
context.quiz = frappe._dict()
|
||||
context.quiz.edit_mode = 1
|
||||
else:
|
||||
fields_arr = []
|
||||
for num in range(1,5):
|
||||
fields_arr.append("option_" + cstr(num))
|
||||
fields_arr.append("is_correct_" + cstr(num))
|
||||
fields_arr.append("explanation_" + cstr(num))
|
||||
fields_arr.append("question")
|
||||
context.quiz = frappe.db.get_value("LMS Quiz", quizname, ["title"], as_dict=1)
|
||||
context.quiz.questions = frappe.get_all("LMS Quiz Question", {
|
||||
"parent": quizname
|
||||
}, fields_arr)
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
{% block content %}
|
||||
<div class="common-page-style">
|
||||
<div class="container">
|
||||
<a class="btn btn-primary btn-sm pull-right"> {{ _("Add Quiz") }} </a>
|
||||
{% if quiz_list | length %}
|
||||
<a class="btn btn-secondary btn-sm pull-right" href="/quizzes/new-quiz"> {{ _("Add Quiz") }} </a>
|
||||
<div class="course-home-headings"> {{ _("Quiz List") }} </div>
|
||||
<div class="common-card-style">
|
||||
<table class="table">
|
||||
@@ -24,12 +25,23 @@
|
||||
<tr style="position: relative; color: var(--text-color);">
|
||||
<td> {{ loop.index }} </td>
|
||||
<td>
|
||||
<a class="button-links" href="/courses/quiz/{{ quiz.name }}">{{ quiz.name }}</a>
|
||||
<a class="button-links" href="/quizzes/{{ quiz.name }}">{{ quiz.name }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-state-text">
|
||||
<div class="empty-state-heading">{{ _("You have not created any quiz yet.") }}</div>
|
||||
<div class="course-meta mb-6">{{ _("Create a quiz and add it to your course to engage users.") }}</div>
|
||||
<a class="btn btn-secondary btn-sm"
|
||||
href="{% if frappe.session.user == 'Guest' %} /login?redirect-to=/quizzes {% else %} /quizzes/new-quiz {% endif %}">
|
||||
{{ _("Add Quiz") }} </a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -336,7 +336,7 @@ const save_course = (e) => {
|
||||
"video_link": $("#video-link").text(),
|
||||
"image": $("#image").attr("href"),
|
||||
"description": $("#description").text(),
|
||||
"course": $("#title").data("course")
|
||||
"course": $("#title").data("course") ? $("#title").data("course") : ""
|
||||
},
|
||||
callback: (data) => {
|
||||
window.location.href = `/courses/${data.message}?edit=1`;
|
||||
@@ -344,6 +344,7 @@ const save_course = (e) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const remove_tag = (e) => {
|
||||
$(e.currentTarget).closest(".course-card-pills").remove();
|
||||
};
|
||||
|
||||
@@ -11,6 +11,8 @@ def get_context(context):
|
||||
redirect_to_courses_list()
|
||||
|
||||
if course_name == "new-course":
|
||||
if frappe.session.user == "Guest":
|
||||
redirect_to_courses_list()
|
||||
context.course = frappe._dict()
|
||||
context.course.edit_mode = True
|
||||
context.membership = None
|
||||
|
||||
Reference in New Issue
Block a user