test: fixed course creation test

This commit is contained in:
Jannat Patel
2023-05-10 19:35:45 +05:30
parent 752fe5b4ba
commit 0e444ab7d3
20 changed files with 372 additions and 675 deletions
-6
View File
@@ -59,12 +59,6 @@
</button>
</div>
</div>
</div>
</header>
{% endmacro %}
+36 -1
View File
@@ -122,7 +122,6 @@ const parse_lesson_to_string = (data) => {
? `{{ Video("${url}") }}\n`
: `![](${url})`;
} else if (block.type == "header") {
console.log(block);
lesson_content +=
"#".repeat(block.data.level) + ` ${block.data.text}\n`;
} else if (block.type == "paragraph") {
@@ -133,6 +132,7 @@ const parse_lesson_to_string = (data) => {
};
const save = (lesson_content) => {
validate_mandatory(lesson_content);
let lesson = $("#lesson-title").data("lesson");
frappe.call({
@@ -157,6 +157,28 @@ const save = (lesson_content) => {
});
};
const validate_mandatory = (lesson_content) => {
if (!$("#lesson-title").val()) {
let error = $("p")
.addClass("error-message")
.text(__("Please enter a Lesson Title"));
$(error).insertAfter("#lesson-title");
$("#lesson-title").focus();
throw "Title is mandatory";
}
if (!lesson_content.trim()) {
let error = $("p")
.addClass("error-message")
.text(__("Please enter some content for the lesson"));
$(error).insertAfter("#lesson-content");
document
.getElementById("lesson-content")
.scrollIntoView({ block: "start" });
throw "Lesson Content is mandatory";
}
};
const fetch_quiz_list = () => {
frappe.call({
method: "lms.lms.doctype.lms_quiz.lms_quiz.get_user_quizzes",
@@ -205,6 +227,19 @@ class YouTubeVideo {
label: __("YouTube Video ID"),
reqd: 1,
},
{
fieldname: "instructions_section_break",
fieldtype: "Section Break",
label: __("Instructions:"),
},
{
fieldname: "instructions",
fieldtype: "HTML",
label: __("Instructions"),
options: __(
"Enter the YouTube Video ID. The ID is the part of the URL after <code>watch?v=</code>. For example, if the URL is <code>https://www.youtube.com/watch?v=QH2-TGUlwu4</code>, the ID is <code>QH2-TGUlwu4</code>"
),
},
],
primary_action_label: __("Insert"),
primary_action(values) {
-116
View File
@@ -1,7 +1,6 @@
frappe.ready(() => {
this.marked_as_complete = false;
this.quiz_submitted = false;
this.file_type;
this.answer = [];
this.is_correct = [];
let self = this;
@@ -12,8 +11,6 @@ frappe.ready(() => {
save_current_lesson();
set_file_type();
$(".option").click((e) => {
enable_check(e);
});
@@ -64,14 +61,6 @@ frappe.ready(() => {
clear_work(e);
});
$(".btn-lesson").click((e) => {
save_lesson(e);
});
$(".add-attachment").click((e) => {
show_upload_modal();
});
$(".btn-start-quiz").click((e) => {
$("#start-banner").addClass("hide");
$("#quiz-form").removeClass("hide");
@@ -95,16 +84,6 @@ frappe.ready(() => {
}
});
}
if ($("#body").length) {
make_editor();
}
$("#file-type").change((e) => {
$("#file-type option:selected").each(function () {
self.file_type = $(this).val();
});
});
});
const save_current_lesson = () => {
@@ -522,98 +501,3 @@ const calculate_and_display_time = (percent_time) => {
let progress_color = percent_time < 20 ? "red" : "var(--primary-color)";
$(".timer .progress-bar").css("background-color", progress_color);
};
const save_lesson = (e) => {
let lesson = $("#title").data("lesson");
let self = this;
frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.save_lesson",
args: {
title: $("#title").text(),
body: this.code_field_group.fields_dict["code_md"].value,
youtube: $("#youtube").text(),
quiz_id: $("#quiz-id").text(),
chapter: $("#title").data("chapter"),
preview: $("#preview").prop("checked") ? 1 : 0,
idx: $("#title").data("index"),
lesson: lesson ? lesson : "",
question: $("#assignment-question").text(),
file_type: self.file_type,
},
callback: (data) => {
frappe.show_alert({
message: __("Saved"),
indicator: "green",
});
setTimeout(() => {
window.location.href = window.location.href.split("?")[0];
}, 1000);
},
});
};
const show_upload_modal = () => {
new frappe.ui.FileUploader({
folder: "Home/Attachments",
restrictions: {
allowed_file_types: ["image/*", "video/*"],
},
on_success: (file_doc) => {
$(".attachments").append(build_attachment_table(file_doc));
let count = $(".attachment-count").data("count") + 1;
$(".attachment-count").data("count", count);
$(".attachment-count").html(__(`${count} attachments`));
$(".attachments").removeClass("hide");
},
});
};
const build_attachment_table = (file_doc) => {
let video_types = ["mov", "mp4", "mkv"];
let video_extension = file_doc.file_url.split(".").pop();
let is_video = video_types.indexOf(video_extension) >= 0;
let link = is_video
? `{{ Video('${file_doc.file_url}') }}`
: `![](${file_doc.file_url})`;
return $(`
<tr class="attachment-row">
<td>${file_doc.file_name}</td>
<td class="">
<a class="button is-secondary button-links copy-link" data-link="${link}"
data-name="${file_doc.file_name}" > ${__("Copy Link")}
</a>
</td>
</tr>
`);
};
const make_editor = () => {
/* this.code_field_group = new frappe.ui.FieldGroup({
fields: [
{
fieldname: "code_md",
fieldtype: "Text Editor",
default: $(".body-data").html(),
},
],
body: $("#body").get(0),
});
this.code_field_group.make();
$("#body .form-section:last").removeClass("empty-section");
$("#body .frappe-control").removeClass("hide-control");
$("#body .form-column").addClass("p-0"); */
};
const set_file_type = () => {
let self = this;
let file_type = $("#file-type").data("type");
if (file_type) {
$("#file-type option").each((i, elem) => {
if ($(elem).val() == file_type) {
$(elem).attr("selected", true);
self.file_type = file_type;
}
});
}
};
+99 -88
View File
@@ -1,6 +1,6 @@
{% extends "templates/base.html" %}
{% block title %}
{{ _("Quiz List") }}
{{ quiz.title if quiz.name else _("Quiz Details") }}
{% endblock %}
@@ -8,11 +8,25 @@
<div class="common-page-style">
{{ Header() }}
<div class="container form-width">
{{ QuizCard(quiz) }}
{{ QuizForm(quiz) }}
</div>
</div>
{% endblock %}
{% macro QuizForm(quiz) %}
<div>
{{ QuizDetails(quiz) }}
{% if quiz.questions %}
{% for question in quiz.questions %}
{{ Question(question, loop.index) }}
{% endfor %}
{% endif %}
<div id="question-template" class="hide">
{{ Question({}, 0) }}
</div>
</div>
{% endmacro %}
{% macro Header() %}
<header class="sticky">
<div class="container form-width">
@@ -30,104 +44,101 @@
</div>
</div>
<button class="btn btn-primary btn-sm btn-save-question align-self-center">
{{ _("Save") }}
</button>
<div class="align-self-center">
<button class="btn btn-default btn-sm btn-add-question">
{{ _("Add Question") }}
</button>
<button class="btn btn-primary btn-sm btn-save-question">
{{ _("Save") }}
</button>
</div>
</div>
</div>
</header>
{% endmacro %}
{% macro QuizCard(quiz) %}
<div>
<div class="field-parent">
<div class="field-group">
<div>
<div class="field-label">
{{ _("Title") }}
</div>
<div class="field-description">
{{ _("Give your quiz a title") }}
</div>
{% macro QuizDetails(quiz) %}
<div class="field-parent">
<div class="field-group">
<div>
<div class="field-label">
{{ _("Title") }}
</div>
<div class="">
<input type="text" class="field-input" id="quiz-title" {% if quiz.name %} value="{{ quiz.title }}" data-name="{{ quiz.name }}" {% endif %}>
<div class="field-description">
{{ _("Give your quiz a title") }}
</div>
</div>
</div>
{% if quiz.questions %}
{% for question in quiz.questions %}
<div class="common-card-style column-card field-parent">
<div class="field-group">
<div>
<div class="field-label">
{{ _("Question") }} {{ loop.index }}
</div>
</div>
<div class="">
<input type="text" class="field-input question" {% if question.name %} value="{{ question.question }}" data-question="{{ question.name }}" {% endif %}>
</div>
</div>
<div class="field-group">
<div class="vertically-center justify-content-between">
<div class="field-label">
{{ _("Question Type") }}
</div>
<div class="btn-group btn-group-toggle type align-self-center" data-toggle="buttons">
<label class="btn btn-default btn-sm active question-type">
<input type="radio" name="type-{{ loop.index }}" data-type="Choices" {% if question.type == "Choices" %} checked {% endif %}>
{{ _("Choices") }}
</label>
<label class="btn btn-default btn-sm question-type">
<input type="radio" name="type-{{ loop.index }}" data-type="User Input" {% if question.type == "User Input" %} checked {% endif %}>
{{ _("User Input") }}
</label>
</div>
</div>
</div>
<div class="">
{% for i in range(1,5) %}
{% set num = frappe.utils.cstr(i) %}
{% set option = question["option_" + num] %}
{% set explanation = question["explanation_" + num] %}
{% set possible_answer = question["possibility_" + num] %}
<div class="field-group">
<div class="options-group {% if question.type == 'User Input' %} hide {% endif %}">
<input type="text" placeholder="Option" class="field-input option-{{ num }}" {% if option %} value="{{ option }}" {% endif %}>
<input type="text" placeholder="Explanation" class="field-input explanation-{{ num }}" {% if explanation %} value="{{ explanation }}" {% endif %}>
<label class="vertically-center mt-1">
<input type="checkbox" class="correct-{{ num }}" {% if question['is_correct_' + num] %} checked {% endif %}>
{{ _("Is Correct") }}
</label>
</div>
<div class="answers-group {% if question.type == 'Choices' %} hide {% endif %}">
<div class="field-label">
{{ _("Possible Answers") }} {{ num }}
</div>
<textarea class="field-input possibility-{{ num }}"
style="height: 100px;">{% if possible_answer %}{{ possible_answer }}{% endif %}</textarea>
</div>
</div>
{% endfor %}
<input type="text" class="field-input" id="quiz-title" {% if quiz.name %} value="{{ quiz.title }}" data-name="{{ quiz.name }}" {% endif %}>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endmacro %}
{% macro Question(question, index) %}
{% set type = question.type if question.type else "Choices" %}
<div class="common-card-style column-card field-parent question-card" data-index="{{ index }}">
<div class="field-group">
<div>
<div class="field-label question-label">
{{ _("Question") }} {{ index }}
</div>
</div>
<div class="">
<input type="text" class="field-input question" {% if question.name %} value="{{ question.question }}" data-question="{{ question.name }}" {% endif %}>
</div>
</div>
<div class="field-group">
<div class="vertically-center justify-content-between">
<div class="field-label">
{{ _("Question Type") }}
</div>
<div class="btn-group btn-group-toggle type align-self-center" data-toggle="buttons">
<label class="btn btn-default btn-sm active question-type">
<input type="radio" name="type-{{ index }}" data-type="Choices" {% if type == "Choices" %} checked {% endif %}>
{{ _("Choices") }}
</label>
<label class="btn btn-default btn-sm question-type">
<input type="radio" name="type-{{ index }}" data-type="User Input" {% if type == "User Input" %} checked {% endif %}>
{{ _("User Input") }}
</label>
</div>
</div>
</div>
<div class="">
{% for i in range(1,5) %}
{% set num = frappe.utils.cstr(i) %}
{% set option = question["option_" + num] %}
{% set explanation = question["explanation_" + num] %}
{% set possible_answer = question["possibility_" + num] %}
<div class="field-group">
<div class="options-group {% if type == 'User Input' %} hide {% endif %}">
<input type="text" placeholder="Option" class="field-input option-{{ num }}" {% if option %} value="{{ option }}" {% endif %}>
<input type="text" placeholder="Explanation" class="field-input explanation-{{ num }}" {% if explanation %} value="{{ explanation }}" {% endif %}>
<label class="vertically-center mt-1">
<input type="checkbox" class="correct-{{ num }}" {% if question['is_correct_' + num] %} checked {% endif %}>
{{ _("Is Correct") }}
</label>
</div>
<div class="answers-group {% if type == 'Choices' %} hide {% endif %}">
<div class="field-label">
{{ _("Possible Answers") }} {{ num }}
</div>
<textarea class="field-input possibility-{{ num }}"
style="height: 100px;">{% if possible_answer %}{{ possible_answer }}{% endif %}</textarea>
</div>
</div>
{% endfor %}
</div>
</div>
{% endmacro %}
+23 -70
View File
@@ -1,6 +1,10 @@
frappe.ready(() => {
$(".btn-question").click((e) => {
if ($(".question-card").length <= 1) {
add_question();
}
$(".btn-add-question").click((e) => {
add_question(true);
});
$(".btn-save-question").click((e) => {
@@ -11,7 +15,7 @@ frappe.ready(() => {
frappe.utils.copy_to_clipboard($(e.currentTarget).data("name"));
});
$(".question-type").click((e) => {
$(document).on("click", ".question-type", (e) => {
toggle_form($(e.currentTarget));
});
@@ -43,72 +47,21 @@ const toggle_form = (el) => {
}
};
const add_question = () => {
let add_after = $(".quiz-card").length
? $(".quiz-card:last")
: $("#quiz-title");
let question_template = `<div class="quiz-card new-quiz-card">
<div contenteditable="true" data-placeholder="${__(
"Question"
)}" class="question mb-4"></div>
<select value="{{ question.type }}" class="input-with-feedback form-control ellipsis type" maxlength="140" data-fieldtype="Select" data-fieldname="type" placeholder="" data-doctype="LMS Quiz Question">
<option value="Choices"> ${__("Choices")} </option>
<option value="User Input"> ${__("User Input")} </option>
</select>
</div>`;
$(question_template).insertAfter(add_after);
get_question_template();
$(".btn-save-question").removeClass("hide");
const add_question = (scroll = false) => {
let template = $("#question-template").html();
let index = $(".question-card:nth-last-child(2)").data("index") + 1 || 1;
template = update_index(template, index);
$(template).insertBefore($("#question-template"));
scroll && scroll_to_question_container();
};
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()
: $(".type:last");
question_template = $(option_template).insertAfter(add_after);
});
Array.from({ length: 4 }, (x, num) => {
let possibility_template = get_possibility_template(num + 1);
let add_after = $(".quiz-card:last .possibility-group").length
? $(".quiz-card:last .possibility-group").last()
: $(".quiz-card:last .option-group:last");
question_template = $(possibility_template).insertAfter(add_after);
});
};
const get_possibility_template = (num) => {
return `<div class="possibility-group mt-4 hide">
<label class=""> ${__("Possible Answer")} ${num} </label>
<div class="control-input-wrapper">
<div class="control-input">
<div contenteditable="true" class="input-with-feedback form-control bold possibility-{{ num }}" style="height: 100px;" spellcheck="false"></div>
</div>
</div>
</div>`;
};
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 update_index = (template, index) => {
const $template = $(template);
$template.attr("data-index", index);
$template.find(".question-label").text("Question " + index);
$template.find(".question-type input").attr("name", "type-" + index);
return $template.prop("outerHTML");
};
const save_question = (e) => {
@@ -124,7 +77,7 @@ const save_question = (e) => {
quiz: $("#quiz-title").data("name") || "",
},
callback: (data) => {
window.location.reload();
window.location.href = `/quizzes/${data.message}`;
},
});
};
@@ -203,15 +156,15 @@ const validate_mandatory = (details, correct_options, possibilities) => {
};
const scroll_to_question_container = () => {
scroll_to_element(".new-quiz-card:last");
$(".new-quiz-card").find(".question").focus();
scroll_to_element(".question-card:nth-last-child(2)");
$(".question-card:nth-last-child(2)").find(".question").focus();
};
const scroll_to_element = (element) => {
if ($(element).length)
$([document.documentElement, document.body]).animate(
{
scrollTop: $(element).offset().top,
scrollTop: $(element).offset().top - 100,
},
1000
);
+1 -20
View File
@@ -35,7 +35,7 @@
<div class="mt-5">
<ul class="list-unstyled">
{% for quiz in quiz_list %}
<li>
<li class="mt-2">
<a class="clickable" href="/quizzes/{{ quiz.name }}">
{{ quiz.title }}
</a>
@@ -58,22 +58,3 @@
</div>
</div>
{% endmacro %}
{% block script %}
<script>
frappe.ready(() => {
$(".copy-quiz-id").click((e) => {
e.preventDefault();
frappe.utils.copy_to_clipboard($(e.currentTarget).data("name"));
});
$(".quiz-row").click((e) => {
if (!$(e.target).hasClass("copy-quiz-id")) {
window.location.href = `/quizzes/${$(e.currentTarget).data('name')}`;
}
});
});
</script>
{% endblock %}