Merge branch 'main' of https://github.com/frappe/lms into ui-fixes
This commit is contained in:
@@ -139,11 +139,6 @@
|
||||
{% if next_url %} {{ _("Next") }} {% else %} {{ _("Mark as Complete") }} {% endif %}
|
||||
<img class="ml-2" src="/assets/lms/icons/side-arrow-white.svg">
|
||||
</a>
|
||||
{% if course.enable_certification %}
|
||||
<div class="button is-primary {% if membership.progress|int != 100 or next_url %} hide {% endif %}" id="certification">
|
||||
{{ _("Get Certificate") }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -45,6 +45,18 @@ frappe.ready(() => {
|
||||
clear_work(e);
|
||||
});
|
||||
|
||||
$(".btn-start-quiz").click((e) => {
|
||||
$("#start-banner").addClass("hide");
|
||||
$("#quiz-form").removeClass("hide");
|
||||
mark_active_question();
|
||||
});
|
||||
|
||||
if ($("#quiz-title").data("max-attempts")) {
|
||||
window.addEventListener("beforeunload", (e) => {
|
||||
e.returnValue = "";
|
||||
$(".active-question").length && quiz_summary();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const save_current_lesson = () => {
|
||||
@@ -65,19 +77,19 @@ const enable_check = (e) => {
|
||||
};
|
||||
|
||||
const mark_active_question = (e = undefined) => {
|
||||
var current_index;
|
||||
var next_index = 1;
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
current_index = $(".active-question").attr("data-qt-index");
|
||||
next_index = parseInt(current_index) + 1;
|
||||
}
|
||||
$(".question").addClass("hide").removeClass("active-question");
|
||||
$(`.question[data-qt-index='${next_index}']`).removeClass("hide").addClass("active-question");
|
||||
$(".current-question").text(`${next_index}`);
|
||||
$("#check").removeClass("hide").attr("disabled", true);
|
||||
$("#next").addClass("hide");
|
||||
$(".explanation").addClass("hide");
|
||||
$(".timer").addClass("hide");
|
||||
calculate_and_display_time(100);
|
||||
$(".timer").removeClass("hide");
|
||||
|
||||
let current_index = $(".active-question").attr("data-qt-index") || 0;
|
||||
let next_index = parseInt(current_index) + 1;
|
||||
$(".question").addClass("hide").removeClass("active-question");
|
||||
$(`.question[data-qt-index='${next_index}']`).removeClass("hide").addClass("active-question");
|
||||
$(".current-question").text(`${next_index}`);
|
||||
$("#check").removeClass("hide").attr("disabled", true);
|
||||
$("#next").addClass("hide");
|
||||
$(".explanation").addClass("hide");
|
||||
initialize_timer();
|
||||
};
|
||||
|
||||
const mark_progress = (e) => {
|
||||
@@ -85,7 +97,7 @@ const mark_progress = (e) => {
|
||||
if ($(e.currentTarget).prop("nodeName") != "INPUT")
|
||||
e.preventDefault();
|
||||
else
|
||||
return
|
||||
return;
|
||||
|
||||
const target = $(e.currentTarget).attr("data-progress") ? $(e.currentTarget) : $("input.mark-progress");
|
||||
const current_status = $(".lesson-progress").hasClass("hide") ? "Incomplete": "Complete";
|
||||
@@ -152,57 +164,56 @@ const move_to_next_lesson = (status, e) => {
|
||||
}
|
||||
};
|
||||
|
||||
const quiz_summary = (e) => {
|
||||
e.preventDefault();
|
||||
var quiz_name = $("#quiz-title").text();
|
||||
var total_questions = $(".question").length;
|
||||
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary",
|
||||
args: {
|
||||
"quiz": quiz_name,
|
||||
"results": localStorage.getItem(quiz_name)
|
||||
},
|
||||
callback: (data) => {
|
||||
var message = data.message == total_questions ? "Excellent Work" : "You were almost there."
|
||||
$(".question").addClass("hide");
|
||||
$("#summary").addClass("hide");
|
||||
$("#quiz-form").parent().prepend(
|
||||
`<div class="text-center summary"><h2>${message} 👏 </h2>
|
||||
<div class="font-weight-bold">${data.message}/${total_questions} correct.</div></div>`);
|
||||
$("#try-again").removeClass("hide");
|
||||
}
|
||||
})
|
||||
const quiz_summary = (e=undefined) => {
|
||||
e && e.preventDefault();
|
||||
var quiz_name = $("#quiz-title").text();
|
||||
var total_questions = $(".question").length;
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary",
|
||||
args: {
|
||||
"quiz": quiz_name,
|
||||
"results": localStorage.getItem(quiz_name)
|
||||
},
|
||||
callback: (data) => {
|
||||
var message = data.message == total_questions ? __("Excellent Work 👏") : __("Better luck next time")
|
||||
$(".question").addClass("hide");
|
||||
$("#summary").addClass("hide");
|
||||
$("#quiz-form").parent().prepend(
|
||||
`<div class="text-center summary"><h2> ${message} </h2>
|
||||
<div class="font-weight-bold">${data.message}/${total_questions}</div></div>`);
|
||||
$("#try-again").removeClass("hide");
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
const try_quiz_again = (e) => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const check_answer = (e) => {
|
||||
e.preventDefault();
|
||||
const check_answer = (e=undefined) => {
|
||||
e && e.preventDefault();
|
||||
clearInterval(self.timer);
|
||||
$(".timer").addClass("hide");
|
||||
var quiz_name = $("#quiz-title").text();
|
||||
var total_questions = $(".question").length;
|
||||
var current_index = $(".active-question").attr("data-qt-index");
|
||||
|
||||
var quiz_name = $("#quiz-title").text();
|
||||
var total_questions = $(".question").length;
|
||||
var current_index = $(".active-question").attr("data-qt-index");
|
||||
$(".explanation").removeClass("hide");
|
||||
$("#check").addClass("hide");
|
||||
|
||||
$(".explanation").removeClass("hide");
|
||||
$("#check").addClass("hide");
|
||||
|
||||
if (current_index == total_questions) {
|
||||
if ($(".eligible-for-submission").length) {
|
||||
$("#summary").removeClass("hide")
|
||||
if (current_index == total_questions) {
|
||||
if ($(".eligible-for-submission").length) {
|
||||
$("#summary").removeClass("hide");
|
||||
}
|
||||
else {
|
||||
$("#submission-message").removeClass("hide");
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("#submission-message").removeClass("hide");
|
||||
$("#next").removeClass("hide");
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("#next").removeClass("hide")
|
||||
}
|
||||
|
||||
var [answer, is_correct] = parse_options();
|
||||
add_to_local_storage(quiz_name, current_index, answer, is_correct)
|
||||
var [answer, is_correct] = parse_options();
|
||||
add_to_local_storage(quiz_name, current_index, answer, is_correct);
|
||||
};
|
||||
|
||||
const parse_options = () => {
|
||||
@@ -381,3 +392,35 @@ const fetch_assignments = () => {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const initialize_timer = () => {
|
||||
this.time_left = $(".timer").data("time");
|
||||
calculate_and_display_time(100, this.time_left);
|
||||
$(".timer").removeClass("hide");
|
||||
const total_time = $(".timer").data("time");
|
||||
this.start_time = new Date().getTime();
|
||||
const self = this;
|
||||
let old_diff;
|
||||
|
||||
this.timer = setInterval(function () {
|
||||
var diff = (new Date().getTime() - self.start_time)/1000;
|
||||
var variation = old_diff ? diff - old_diff : diff;
|
||||
old_diff = diff;
|
||||
self.time_left -= variation;
|
||||
let percent_time = (self.time_left / total_time) * 100;
|
||||
calculate_and_display_time(percent_time);
|
||||
if (self.time_left <= 0) {
|
||||
clearInterval(self.timer);
|
||||
$(".timer").addClass("hide");
|
||||
check_answer();
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const calculate_and_display_time = (percent_time) => {
|
||||
$(".timer .progress-bar").attr("aria-valuenow", percent_time);
|
||||
$(".timer .progress-bar").attr("aria-valuemax", percent_time);
|
||||
$(".timer .progress-bar").css("width", `${percent_time}%`);
|
||||
let progress_color = percent_time < 20 ? "red" : "var(--primary-color)";
|
||||
$(".timer .progress-bar").css("background-color", progress_color);
|
||||
};
|
||||
|
||||
@@ -5,18 +5,23 @@
|
||||
<div class="common-page-style">
|
||||
<div class="container certificate-page">
|
||||
|
||||
{% if certificate.member == frappe.session.user %}
|
||||
<!-- {% if certificate.member == frappe.session.user %}
|
||||
<div class="button is-secondary pull-right mt-4" id="export-as-pdf" data-certificate="{{ certificate.name }}"
|
||||
data-certificate-name="{{ member.full_name }} - {{ course.title }}">{{ _("Export") }}</div>
|
||||
{% endif %}
|
||||
{% endif %} -->
|
||||
|
||||
<div class="breadcrumb">
|
||||
<a class="dark-links" href="/courses">{{ _("All Courses") }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<a class="dark-links" href="/courses/{{ course.name }}">{{ course.title }}</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if custom_template %}
|
||||
{{ custom_template }}
|
||||
{% else %}
|
||||
{% include "lms/templates/certificate.html" %}
|
||||
{% endif %}
|
||||
<script src="/assets/lms/js/html2canvas.js"></script>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
$("#export-as-pdf").click((e) => {
|
||||
export_as_pdf(e);
|
||||
})
|
||||
$("#export-as-pdf").click((e) => {
|
||||
export_as_pdf(e);
|
||||
})
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
var export_as_pdf = (e) => {
|
||||
var button = $(e.currentTarget);
|
||||
button.text(__("Exporting..."));
|
||||
const export_as_pdf = (e) => {
|
||||
let button = $(e.currentTarget);
|
||||
button.text(__("Exporting..."));
|
||||
|
||||
html2canvas(document.querySelector('.common-card-style'), {
|
||||
html2canvas(document.querySelector('.certificate-card'), {
|
||||
scrollY: -window.scrollY,
|
||||
scrollX: 0
|
||||
}).then(function(canvas) {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import frappe
|
||||
from frappe.utils.jinja import render_template
|
||||
from lms.lms.utils import get_instructors
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
@@ -15,16 +17,21 @@ def get_context(context):
|
||||
if context.certificate.course != course_name:
|
||||
redirect_to_course_list()
|
||||
|
||||
context.course = frappe.db.get_value("LMS Course", course_name,
|
||||
["instructor", "title", "name"], as_dict=True)
|
||||
|
||||
context.instructor = frappe.db.get_value("User", context.course.instructor,
|
||||
["full_name", "username"], as_dict=True)
|
||||
|
||||
context.course = frappe.db.get_value("LMS Course", course_name, ["title", "name", "image"], as_dict=True)
|
||||
context.instructors = (", ").join([x.full_name for x in get_instructors(course_name)])
|
||||
context.member = frappe.db.get_value("User", context.certificate.member,
|
||||
["full_name"], as_dict=True)
|
||||
|
||||
context.logo = frappe.db.get_single_value("Website Settings", "banner_image")
|
||||
template_name = frappe.db.get_single_value("LMS Settings", "custom_certificate_template")
|
||||
context.custom_certificate_template = frappe.db.get_value("Web Template", template_name, "template")
|
||||
context.custom_template = render_template(context.custom_certificate_template, context)
|
||||
|
||||
context.metatags = {
|
||||
"title": f"{member.full_name} - {course.title}",
|
||||
"image": course.image,
|
||||
"keywords": course.title, member.full_name
|
||||
}
|
||||
|
||||
def redirect_to_course_list():
|
||||
frappe.local.flags.redirect_location = "/courses"
|
||||
|
||||
Reference in New Issue
Block a user