Merge branch 'main' into 644

This commit is contained in:
Jannat Patel
2023-10-26 14:45:56 +05:30
committed by GitHub
44 changed files with 1234 additions and 461 deletions

View File

@@ -127,7 +127,7 @@
{%- block script %}
{{ super() }}
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/@editorjs/paragraph@2.10.0"></script>
<script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script>
<script src="https://cdn.jsdelivr.net/npm/@editorjs/embed@latest"></script>
{% endblock %}

View File

@@ -429,9 +429,9 @@ class Quiz {
}
render_quiz(quiz) {
return `<div class="common-card-style p-2 my-2 bold-heading">
return `<a class="common-card-style p-20 my-2 justify-center bold-heading" target="_blank" href=/quizzes/${quiz}>
Quiz: ${quiz}
</div>`;
</a>`;
}
validate(savedData) {

View File

@@ -16,25 +16,9 @@
{% macro QuizForm(quiz) %}
<div id="quiz-form" {% if quiz.name %} data-name="{{ quiz.name }}" data-index="{{ quiz.questions | length }}" {% endif %}>
{{ QuizDetails(quiz) }}
{% if quiz.questions %}
<div class="field-group">
<div class="field-label mb-1">
{{ _("Questions") }}
</div>
<div class="common-card-style column-card px-3 py-0">
{% for question in quiz.questions %}
{{ Question(question, loop.index) }}
{% endfor %}
</div>
<button class="btn btn-secondary btn-sm btn-add-question mt-4">
{{ _("Add Question") }}
</button>
</div>
{% endif %}
{% if quiz.name and not quiz.questions | length %}
{{ EmptyState() }}
{% endif %}
<div class="field-group">
<div class="questions-table"></div>
</div>
</div>
{% endmacro %}
@@ -59,11 +43,6 @@
</div>
<div class="align-self-center">
{% if quiz.name %}
<button class="btn btn-secondary btn-sm btn-add-question mr-2">
{{ _("Add Question") }}
</button>
{% endif %}
<button class="btn btn-primary btn-sm btn-save-quiz">
{{ _("Save") }}
</button>
@@ -98,18 +77,30 @@
{{ _("Enter the maximum number of times a user can attempt this quiz") }}
</div>
<div>
{% set max_attempts = quiz.max_attempts if quiz.name else 1 %}
{% set max_attempts = quiz.max_attempts if quiz.name else 0 %}
<input type="number" class="field-input" id="max-attempts" value="{{ max_attempts }}">
</div>
</div>
<div class="field-group">
<div class="field-label reqd">
{{ _("Passing Percentage") }}
</div>
<div class="field-description">
{{ _("Minimum percentage required to pass this quiz.") }}
</div>
<div>
<input type="number" class="field-input" id="passing-percentage" value="{{ quiz.passing_percentage }}">
</div>
</div>
<div class="field-group vertically-center">
{% set show_answers = quiz.show_answers or not quiz.name %}
<label for="show-answers" class="vertically-center mb-0">
<input type="checkbox" id="show-answers" {% if show_answers %} checked {% endif %}>
{{ _("Show Answers") }}
</label>
<label for="upcoming" class="vertically-center mb-0 ml-20">
<label for="show-submission-history" class="vertically-center mb-0 ml-20">
<input type="checkbox" id="show-submission-history" {% if quiz.show_submission_history %} checked {% endif %}>
{{ _("Show Submission History") }}
</label>
@@ -151,5 +142,9 @@
{%- block script %}
{{ super() }}
{{ include_script('controls.bundle.js') }}
{% if has_course_instructor_role() or has_course_moderator_role() %}
<script>
const quiz_questions = {{ quiz.questions or [] }}
</script>
{% endif %}
{% endblock %}

View File

@@ -1,17 +1,21 @@
frappe.ready(() => {
$(".btn-save-quiz").click((e) => {
save_quiz({
quiz_title: $("#quiz-title").val(),
max_attempts: $("#max-attempts").val(),
if ($(".questions-table").length) {
frappe.require("controls.bundle.js", () => {
create_questions_table();
});
}
$(".btn-save-quiz").click((e) => {
save_quiz();
});
$(".question-row").click((e) => {
edit_question(e);
});
$(".btn-add-question").click((e) => {
show_question_modal();
$(document).on("click", ".questions-table .link-btn", (e) => {
e.preventDefault();
fetch_question_data(e);
});
});
@@ -31,6 +35,8 @@ const show_question_modal = (values = {}) => {
};
const get_question_fields = (values = {}) => {
if (!values.question) values = {};
let dialog_fields = [
{
fieldtype: "Text Editor",
@@ -66,6 +72,7 @@ const get_question_fields = (values = {}) => {
if (num <= 2) option.mandatory_depends_on = "eval:doc.type=='Choices'";
dialog_fields.push(option);
console.log(dialog_fields);
dialog_fields.push({
fieldtype: "Data",
@@ -120,12 +127,16 @@ const edit_question = (e) => {
const save_quiz = (values) => {
validate_mandatory();
validate_questions();
frappe.call({
method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz",
args: {
quiz_title: values.quiz_title,
max_attempts: values.max_attempts,
quiz_title: $("#quiz-title").val(),
max_attempts: $("#max-attempts").val(),
passing_percentage: $("#passing-percentage").val(),
quiz: $("#quiz-form").data("name") || "",
questions: this.table.get_value("questions"),
show_answers: $("#show-answers").is(":checked") ? 1 : 0,
show_submission_history: $("#show-submission-history").is(
":checked"
@@ -146,13 +157,45 @@ const save_quiz = (values) => {
};
const validate_mandatory = () => {
if (!$("#quiz-title").val()) {
let error = $("p")
.addClass("error-message")
.text(__("Please enter a Quiz Title"));
$(error).insertAfter("#quiz-title");
$("#quiz-title").focus();
throw "Title is mandatory";
let fields = ["#quiz-title", "#passing-percentage"];
fields.forEach((field, idx) => {
if (!$(field).val()) {
let error = $("p")
.addClass("error-message")
.text(__("Please enter a value"));
$(error).insertAfter(field);
scroll_to_element($(field));
throw "This field is mandatory";
}
});
};
const validate_questions = () => {
let questions = this.table.get_value("questions");
if (!questions.length) {
frappe.throw(__("Please add a question."));
}
questions.forEach((question, index) => {
if (!question.question) {
frappe.throw(__("Please add question in row") + " " + (index + 1));
}
if (!question.marks) {
frappe.throw(__("Please add marks in row") + " " + (index + 1));
}
});
};
const scroll_to_element = (element) => {
if ($(element).length) {
$([document.documentElement, document.body]).animate(
{
scrollTop: $(element).offset().top - 100,
},
1000
);
}
};
@@ -167,13 +210,98 @@ const save_question = (values) => {
callback: (data) => {
if (data.message) this.question_dialog.hide();
frappe.show_alert({
message: __("Saved"),
indicator: "green",
});
setTimeout(() => {
window.location.reload();
}, 1000);
if (values.name) {
frappe.show_alert({
message: __("Saved"),
indicator: "green",
});
setTimeout(() => {
window.location.reload();
}, 1000);
} else {
let details = {
question: data.message,
};
index = this.table.get_value("questions").length;
add_question_row(details, index);
}
},
});
};
const create_questions_table = () => {
this.table = new frappe.ui.FieldGroup({
fields: [
{
fieldname: "questions",
fieldtype: "Table",
in_place_edit: 1,
label: __("Questions"),
fields: [
{
fieldname: "question",
fieldtype: "Link",
label: __("Question"),
options: "LMS Question",
in_list_view: 1,
only_select: 1,
reqd: 1,
},
{
fieldname: "marks",
fieldtype: "Int",
label: __("Marks"),
in_list_view: 1,
reqd: 1,
},
{
fieldname: "question_name",
fieldname: "Link",
options: "LMS Quiz Question",
label: __("Question Name"),
},
],
},
],
body: $(".questions-table").get(0),
});
this.table.make();
$(".questions-table .form-section:last").removeClass("empty-section");
$(".questions-table .frappe-control").removeClass("hide-control");
$(".questions-table .form-column").addClass("p-0");
quiz_questions.forEach((question, idx) => {
add_question_row(question, idx);
});
this.table.fields_dict["questions"].grid.add_custom_button(
"New Question",
show_question_modal,
"bottom"
);
};
const add_question_row = (question, idx) => {
this.table.fields_dict["questions"].grid.add_new_row();
this.table.get_value("questions")[idx] = {
question: question.question,
marks: question.marks,
};
this.table.refresh();
};
const fetch_question_data = (e) => {
let question_name = $(e.currentTarget)
.find(".btn-open")
.attr("href")
.split("/")[3];
frappe.call({
method: "lms.lms.doctype.lms_question.lms_question.get_question_details",
args: {
question: question_name,
},
callback: (data) => {
show_question_modal(data.message);
},
});
};

View File

@@ -18,14 +18,22 @@ def get_context(context):
if quizname == "new-quiz":
context.quiz = frappe._dict()
else:
fields_arr = ["name", "question", "type"]
context.quiz = frappe.db.get_value(
"LMS Quiz",
quizname,
["title", "name", "max_attempts", "show_answers", "show_submission_history"],
[
"title",
"name",
"max_attempts",
"passing_percentage",
"show_answers",
"show_submission_history",
],
as_dict=1,
)
fields_arr = ["name", "question", "marks"]
context.quiz.questions = frappe.get_all(
"LMS Quiz Question", {"parent": quizname}, fields_arr, order_by="idx"
)