fix: pre commit issues
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
batch_name = frappe.form_dict["batch"]
|
||||
context.batch = frappe.get_doc("LMS Batch", batch_name)
|
||||
context.already_a_member = context.batch.is_member(frappe.session.user)
|
||||
context.batch.course_title = frappe.db.get_value("LMS Course", context.batch.course, "title")
|
||||
context.no_cache = 1
|
||||
batch_name = frappe.form_dict["batch"]
|
||||
context.batch = frappe.get_doc("LMS Batch", batch_name)
|
||||
context.already_a_member = context.batch.is_member(frappe.session.user)
|
||||
context.batch.course_title = frappe.db.get_value(
|
||||
"LMS Course", context.batch.course, "title"
|
||||
)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
this.marked_as_complete = false;
|
||||
this.quiz_submitted = false;
|
||||
this.file_type;
|
||||
@@ -19,7 +18,11 @@ frappe.ready(() => {
|
||||
|
||||
$(window).scroll(() => {
|
||||
let self = this;
|
||||
if (!$("#status-indicator").length && !self.marked_as_complete && $(".title").hasClass("is-member")) {
|
||||
if (
|
||||
!$("#status-indicator").length &&
|
||||
!self.marked_as_complete &&
|
||||
$(".title").hasClass("is-member")
|
||||
) {
|
||||
self.marked_as_complete = true;
|
||||
mark_progress();
|
||||
}
|
||||
@@ -94,32 +97,31 @@ frappe.ready(() => {
|
||||
}
|
||||
|
||||
$("#file-type").change((e) => {
|
||||
$("#file-type option:selected" ).each(function() {
|
||||
$("#file-type option:selected").each(function () {
|
||||
self.file_type = $(this).val();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
const save_current_lesson = () => {
|
||||
if ($(".title").hasClass("is-member")) {
|
||||
frappe.call("lms.lms.api.save_current_lesson", {
|
||||
course_name: $(".title").attr("data-course"),
|
||||
lesson_name: $(".title").attr("data-lesson")
|
||||
lesson_name: $(".title").attr("data-lesson"),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const enable_check = (e) => {
|
||||
if ($(".option:checked").length) {
|
||||
$("#check").removeAttr("disabled");
|
||||
$(".custom-checkbox").removeClass("active-option");
|
||||
$(".option:checked").closest(".custom-checkbox").addClass("active-option");
|
||||
$(".option:checked")
|
||||
.closest(".custom-checkbox")
|
||||
.addClass("active-option");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const mark_active_question = (e = undefined) => {
|
||||
$(".timer").addClass("hide");
|
||||
calculate_and_display_time(100);
|
||||
@@ -129,7 +131,9 @@ const mark_active_question = (e = undefined) => {
|
||||
let next_index = parseInt(current_index) + 1;
|
||||
|
||||
$(".question").addClass("hide").removeClass("active-question");
|
||||
$(`.question[data-qt-index='${next_index}']`).removeClass("hide").addClass("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");
|
||||
@@ -137,36 +141,37 @@ const mark_active_question = (e = undefined) => {
|
||||
initialize_timer();
|
||||
};
|
||||
|
||||
|
||||
const mark_progress = () => {
|
||||
let status = "Complete"
|
||||
let status = "Complete";
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.course_lesson.course_lesson.save_progress",
|
||||
args: {
|
||||
lesson: $(".title").attr("data-lesson"),
|
||||
course: $(".title").attr("data-course"),
|
||||
status: status
|
||||
status: status,
|
||||
},
|
||||
callback: (data) => {
|
||||
change_progress_indicators();
|
||||
show_certificate_if_course_completed(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const change_progress_indicators = () => {
|
||||
$(".active-lesson .lesson-progress-tick").removeClass("hide");
|
||||
};
|
||||
|
||||
|
||||
const show_certificate_if_course_completed = (data) => {
|
||||
if (data.message == 100 && !$(".next").length && $("#certification").hasClass("hide")) {
|
||||
if (
|
||||
data.message == 100 &&
|
||||
!$(".next").length &&
|
||||
$("#certification").hasClass("hide")
|
||||
) {
|
||||
$("#certification").removeClass("hide");
|
||||
}
|
||||
};
|
||||
|
||||
const quiz_summary = (e=undefined) => {
|
||||
const quiz_summary = (e = undefined) => {
|
||||
e && e.preventDefault();
|
||||
let quiz_name = $("#quiz-title").data("name");
|
||||
let total_questions = $(".question").length;
|
||||
@@ -175,31 +180,35 @@ const quiz_summary = (e=undefined) => {
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary",
|
||||
args: {
|
||||
"quiz": quiz_name,
|
||||
"results": localStorage.getItem(quiz_name)
|
||||
quiz: quiz_name,
|
||||
results: localStorage.getItem(quiz_name),
|
||||
},
|
||||
callback: (data) => {
|
||||
let message = data.message == total_questions ? __("Excellent Work 👏") : __("Better luck next time")
|
||||
let 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">
|
||||
$("#quiz-form")
|
||||
.parent()
|
||||
.prepend(
|
||||
`<div class="text-center summary">
|
||||
<h2> ${message} </h2>
|
||||
<div class="font-weight-bold"> ${data.message}/${total_questions} </div>
|
||||
</div>`);
|
||||
</div>`
|
||||
);
|
||||
$("#try-again").removeClass("hide");
|
||||
self.quiz_submitted = true;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const try_quiz_again = (e) => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
|
||||
const check_answer = (e=undefined) => {
|
||||
const check_answer = (e = undefined) => {
|
||||
e && e.preventDefault();
|
||||
clearInterval(self.timer);
|
||||
$(".timer").addClass("hide");
|
||||
@@ -212,19 +221,16 @@ const check_answer = (e=undefined) => {
|
||||
if (current_index == total_questions) {
|
||||
if ($(".eligible-for-submission").length) {
|
||||
$("#summary").removeClass("hide");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$("#submission-message").removeClass("hide");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$("#next").removeClass("hide");
|
||||
}
|
||||
let [answer, is_correct] = parse_options();
|
||||
add_to_local_storage(current_index, answer, is_correct);
|
||||
};
|
||||
|
||||
|
||||
const parse_options = () => {
|
||||
let answer = [];
|
||||
let is_correct = [];
|
||||
@@ -234,16 +240,16 @@ const parse_options = () => {
|
||||
answer.push(decodeURIComponent($(element).val()));
|
||||
correct && is_correct.push(1);
|
||||
correct ? add_icon(element, "check") : add_icon(element, "wrong");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
correct && is_correct.push(0);
|
||||
correct ? add_icon(element, "minus-circle-green") : add_icon(element, "minus-circle");
|
||||
correct
|
||||
? add_icon(element, "minus-circle-green")
|
||||
: add_icon(element, "minus-circle");
|
||||
}
|
||||
});
|
||||
return [answer, is_correct];
|
||||
};
|
||||
|
||||
|
||||
const add_icon = (element, icon) => {
|
||||
$(element).closest(".custom-checkbox").removeClass("active-option");
|
||||
let label = $(element).siblings(".option-text").text();
|
||||
@@ -256,50 +262,46 @@ const add_icon = (element, icon) => {
|
||||
//$(element).parent().empty().html(`<div class="option-text"><img class="mr-3" src="/assets/lms/icons/${icon}.svg"> ${label}</div>`);
|
||||
};
|
||||
|
||||
|
||||
const add_to_local_storage = (current_index, answer, is_correct) => {
|
||||
let quiz_name = $("#quiz-title").data("name")
|
||||
let quiz_name = $("#quiz-title").data("name");
|
||||
let quiz_stored = JSON.parse(localStorage.getItem(quiz_name));
|
||||
|
||||
let quiz_obj = {
|
||||
"question_index": current_index,
|
||||
"answer": answer.join(),
|
||||
"is_correct": is_correct
|
||||
}
|
||||
question_index: current_index,
|
||||
answer: answer.join(),
|
||||
is_correct: is_correct,
|
||||
};
|
||||
|
||||
quiz_stored ? quiz_stored.push(quiz_obj) : quiz_stored = [quiz_obj]
|
||||
localStorage.setItem(quiz_name, JSON.stringify(quiz_stored))
|
||||
quiz_stored ? quiz_stored.push(quiz_obj) : (quiz_stored = [quiz_obj]);
|
||||
localStorage.setItem(quiz_name, JSON.stringify(quiz_stored));
|
||||
};
|
||||
|
||||
|
||||
const create_certificate = (e) => {
|
||||
e.preventDefault();
|
||||
course = $(".title").attr("data-course");
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
|
||||
args: {
|
||||
"course": course
|
||||
course: course,
|
||||
},
|
||||
callback: (data) => {
|
||||
window.location.href = `/courses/${course}/${data.message.name}`;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const attach_work = (e) => {
|
||||
const target = $(e.currentTarget);
|
||||
let files = target.siblings(".attach-file").prop("files")
|
||||
let files = target.siblings(".attach-file").prop("files");
|
||||
if (files && files.length) {
|
||||
files = add_files(files)
|
||||
return_as_dataurl(files)
|
||||
files = add_files(files);
|
||||
return_as_dataurl(files);
|
||||
files.map((file) => {
|
||||
upload_file(file, target);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const upload_file = (file, target) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
@@ -307,34 +309,39 @@ const upload_file = (file, target) => {
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
let response = JSON.parse(xhr.responseText)
|
||||
let response = JSON.parse(xhr.responseText);
|
||||
create_lesson_work(response.message, target);
|
||||
} else if (xhr.status === 403) {
|
||||
let response = JSON.parse(xhr.responseText);
|
||||
frappe.msgprint(`Not permitted. ${response._error_message || ''}`);
|
||||
|
||||
frappe.msgprint(
|
||||
`Not permitted. ${response._error_message || ""}`
|
||||
);
|
||||
} else if (xhr.status === 413) {
|
||||
frappe.msgprint('Size exceeds the maximum allowed file size.');
|
||||
|
||||
frappe.msgprint(
|
||||
"Size exceeds the maximum allowed file size."
|
||||
);
|
||||
} else {
|
||||
frappe.msgprint(xhr.status === 0 ? 'XMLHttpRequest Error' : `${xhr.status} : ${xhr.statusText}`);
|
||||
frappe.msgprint(
|
||||
xhr.status === 0
|
||||
? "XMLHttpRequest Error"
|
||||
: `${xhr.status} : ${xhr.statusText}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.open('POST', '/api/method/upload_file', true);
|
||||
xhr.setRequestHeader('Accept', 'application/json');
|
||||
xhr.setRequestHeader('X-Frappe-CSRF-Token', frappe.csrf_token);
|
||||
};
|
||||
xhr.open("POST", "/api/method/upload_file", true);
|
||||
xhr.setRequestHeader("Accept", "application/json");
|
||||
xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token);
|
||||
|
||||
let form_data = new FormData();
|
||||
if (file.file_obj) {
|
||||
form_data.append('file', file.file_obj, file.name);
|
||||
form_data.append("file", file.file_obj, file.name);
|
||||
}
|
||||
|
||||
xhr.send(form_data);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const create_lesson_work = (file, target) => {
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lesson_assignment.lesson_assignment.upload_assignment",
|
||||
@@ -345,17 +352,19 @@ const create_lesson_work = (file, target) => {
|
||||
callback: (data) => {
|
||||
target.siblings(".attach-file").addClass("hide");
|
||||
target.siblings(".preview-work").removeClass("hide");
|
||||
target.siblings(".preview-work").find("a").attr("href", file.file_url).text(file.file_name)
|
||||
target
|
||||
.siblings(".preview-work")
|
||||
.find("a")
|
||||
.attr("href", file.file_url)
|
||||
.text(file.file_name);
|
||||
target.addClass("hide");
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const return_as_dataurl = (files) => {
|
||||
let promises = files.map(file =>
|
||||
frappe.dom.file_to_base64(file.file_obj)
|
||||
.then(dataurl => {
|
||||
let promises = files.map((file) =>
|
||||
frappe.dom.file_to_base64(file.file_obj).then((dataurl) => {
|
||||
file.dataurl = dataurl;
|
||||
this.on_success && this.on_success(file);
|
||||
})
|
||||
@@ -363,10 +372,9 @@ const return_as_dataurl = (files) => {
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
|
||||
const add_files = (files) => {
|
||||
files = Array.from(files).map(file => {
|
||||
let is_image = file.type.startsWith('image');
|
||||
files = Array.from(files).map((file) => {
|
||||
let is_image = file.type.startsWith("image");
|
||||
return {
|
||||
file_obj: file,
|
||||
cropper_file: file,
|
||||
@@ -380,13 +388,12 @@ const add_files = (files) => {
|
||||
request_succeeded: false,
|
||||
error_message: null,
|
||||
uploading: false,
|
||||
private: !is_image
|
||||
}
|
||||
private: !is_image,
|
||||
};
|
||||
});
|
||||
return files
|
||||
return files;
|
||||
};
|
||||
|
||||
|
||||
const clear_work = (e) => {
|
||||
const target = $(e.currentTarget);
|
||||
const parent = target.closest(".preview-work");
|
||||
@@ -395,14 +402,12 @@ const clear_work = (e) => {
|
||||
parent.siblings(".submit-work").removeClass("hide");
|
||||
};
|
||||
|
||||
|
||||
const fetch_assignments = () => {
|
||||
if ($(".attach-file").length <= 0)
|
||||
return;
|
||||
if ($(".attach-file").length <= 0) return;
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lesson_assignment.lesson_assignment.get_assignment",
|
||||
args: {
|
||||
"lesson": $(".title").attr("data-lesson")
|
||||
lesson: $(".title").attr("data-lesson"),
|
||||
},
|
||||
callback: (data) => {
|
||||
if (data.message) {
|
||||
@@ -411,13 +416,16 @@ const fetch_assignments = () => {
|
||||
target.addClass("hide");
|
||||
target.siblings(".submit-work").addClass("hide");
|
||||
target.siblings(".preview-work").removeClass("hide");
|
||||
target.siblings(".preview-work").find("a").attr("href", assignment.assignment).text(assignment.file_name);
|
||||
target
|
||||
.siblings(".preview-work")
|
||||
.find("a")
|
||||
.attr("href", assignment.assignment)
|
||||
.text(assignment.file_name);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const initialize_timer = () => {
|
||||
this.time_left = $(".timer").data("time");
|
||||
calculate_and_display_time(100, this.time_left);
|
||||
@@ -428,7 +436,7 @@ const initialize_timer = () => {
|
||||
let old_diff;
|
||||
|
||||
this.timer = setInterval(function () {
|
||||
var diff = (new Date().getTime() - self.start_time)/1000;
|
||||
var diff = (new Date().getTime() - self.start_time) / 1000;
|
||||
var variation = old_diff ? diff - old_diff : diff;
|
||||
old_diff = diff;
|
||||
self.time_left -= variation;
|
||||
@@ -442,7 +450,6 @@ const initialize_timer = () => {
|
||||
}, 100);
|
||||
};
|
||||
|
||||
|
||||
const calculate_and_display_time = (percent_time) => {
|
||||
$(".timer .progress-bar").attr("aria-valuenow", percent_time);
|
||||
$(".timer .progress-bar").attr("aria-valuemax", percent_time);
|
||||
@@ -451,25 +458,24 @@ const calculate_and_display_time = (percent_time) => {
|
||||
$(".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
|
||||
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) => {;
|
||||
callback: (data) => {
|
||||
frappe.show_alert({
|
||||
message: __("Saved"),
|
||||
indicator: "green",
|
||||
@@ -477,16 +483,15 @@ const save_lesson = (e) => {
|
||||
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/*']
|
||||
allowed_file_types: ["image/*", "video/*"],
|
||||
},
|
||||
on_success: (file_doc) => {
|
||||
$(".attachments").append(build_attachment_table(file_doc));
|
||||
@@ -498,12 +503,13 @@ const show_upload_modal = () => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const build_attachment_table = (file_doc) => {
|
||||
let video_types = ["mov", "mp4", "mkv"];
|
||||
let video_extension = file_doc.file_url.split(".").pop();
|
||||
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}') }}` : ``;
|
||||
let link = is_video
|
||||
? `{{ Video('${file_doc.file_url}') }}`
|
||||
: ``;
|
||||
|
||||
return $(`
|
||||
<tr class="attachment-row">
|
||||
@@ -517,7 +523,6 @@ const build_attachment_table = (file_doc) => {
|
||||
`);
|
||||
};
|
||||
|
||||
|
||||
const make_editor = () => {
|
||||
this.code_field_group = new frappe.ui.FieldGroup({
|
||||
fields: [
|
||||
@@ -530,7 +535,7 @@ const make_editor = () => {
|
||||
min_lines: 20,
|
||||
default: $("#body").data("body"),
|
||||
depends_on: 'eval:doc.type=="Markdown"',
|
||||
}
|
||||
},
|
||||
],
|
||||
body: $("#body").get(0),
|
||||
});
|
||||
@@ -540,7 +545,6 @@ const make_editor = () => {
|
||||
$("#body .form-column").addClass("p-0");
|
||||
};
|
||||
|
||||
|
||||
const set_file_type = () => {
|
||||
let self = this;
|
||||
let file_type = $("#file-type").data("type");
|
||||
@@ -550,6 +554,6 @@ const set_file_type = () => {
|
||||
$(elem).attr("selected", true);
|
||||
self.file_type = file_type;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,90 +1,103 @@
|
||||
import frappe
|
||||
from lms.www.utils import get_common_context, redirect_to_lesson
|
||||
from lms.lms.utils import get_lesson_url, has_course_moderator_role, is_instructor
|
||||
from frappe.utils import cstr, flt
|
||||
from frappe import _
|
||||
from frappe.utils import cstr, flt
|
||||
|
||||
from lms.lms.utils import (get_lesson_url, has_course_moderator_role,
|
||||
is_instructor)
|
||||
from lms.www.utils import get_common_context, redirect_to_lesson
|
||||
|
||||
|
||||
def get_context(context):
|
||||
get_common_context(context)
|
||||
get_common_context(context)
|
||||
|
||||
chapter_index = frappe.form_dict.get("chapter")
|
||||
lesson_index = frappe.form_dict.get("lesson")
|
||||
lesson_number = f"{chapter_index}.{lesson_index}"
|
||||
context.lesson_index = lesson_index
|
||||
context.chapter = frappe.db.get_value("Chapter Reference", {
|
||||
"idx": chapter_index,
|
||||
"parent": context.course.name
|
||||
}, "chapter")
|
||||
chapter_index = frappe.form_dict.get("chapter")
|
||||
lesson_index = frappe.form_dict.get("lesson")
|
||||
lesson_number = f"{chapter_index}.{lesson_index}"
|
||||
context.lesson_index = lesson_index
|
||||
context.chapter = frappe.db.get_value(
|
||||
"Chapter Reference", {"idx": chapter_index, "parent": context.course.name}, "chapter"
|
||||
)
|
||||
|
||||
if not chapter_index or not lesson_index:
|
||||
index_ = "1.1"
|
||||
redirect_to_lesson(context.course, index_)
|
||||
if not chapter_index or not lesson_index:
|
||||
index_ = "1.1"
|
||||
redirect_to_lesson(context.course, index_)
|
||||
|
||||
context.lesson = get_current_lesson_details(lesson_number, context)
|
||||
instructor = is_instructor(context.course.name)
|
||||
context.show_lesson = context.membership or (context.lesson and context.lesson.include_in_preview) or instructor or has_course_moderator_role()
|
||||
context.lesson = get_current_lesson_details(lesson_number, context)
|
||||
instructor = is_instructor(context.course.name)
|
||||
context.show_lesson = (
|
||||
context.membership
|
||||
or (context.lesson and context.lesson.include_in_preview)
|
||||
or instructor
|
||||
or has_course_moderator_role()
|
||||
)
|
||||
|
||||
if not context.lesson:
|
||||
context.lesson = frappe._dict()
|
||||
if not context.lesson:
|
||||
context.lesson = frappe._dict()
|
||||
|
||||
if frappe.form_dict.get("edit"):
|
||||
if not instructor and not has_course_moderator_role():
|
||||
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
||||
context.lesson.edit_mode = True
|
||||
else:
|
||||
neighbours = get_neighbours(lesson_number, context.lessons)
|
||||
context.next_url = get_url(neighbours["next"], context.course)
|
||||
context.prev_url = get_url(neighbours["prev"], context.course)
|
||||
if frappe.form_dict.get("edit"):
|
||||
if not instructor and not has_course_moderator_role():
|
||||
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
||||
context.lesson.edit_mode = True
|
||||
else:
|
||||
neighbours = get_neighbours(lesson_number, context.lessons)
|
||||
context.next_url = get_url(neighbours["next"], context.course)
|
||||
context.prev_url = get_url(neighbours["prev"], context.course)
|
||||
|
||||
meta_info = context.lesson.title + " - " + context.course.title if context.lesson.title else "New Lesson"
|
||||
context.metatags = {
|
||||
"title": meta_info,
|
||||
"keywords": meta_info,
|
||||
"description": meta_info
|
||||
}
|
||||
meta_info = (
|
||||
context.lesson.title + " - " + context.course.title
|
||||
if context.lesson.title
|
||||
else "New Lesson"
|
||||
)
|
||||
context.metatags = {
|
||||
"title": meta_info,
|
||||
"keywords": meta_info,
|
||||
"description": meta_info,
|
||||
}
|
||||
|
||||
context.page_extensions = get_page_extensions(context)
|
||||
context.page_context = {
|
||||
"course": context.course.name,
|
||||
"batch": context.batch,
|
||||
"lesson": context.lesson.name if context.lesson.name else "New Lesson",
|
||||
"is_member": context.membership is not None
|
||||
}
|
||||
context.page_extensions = get_page_extensions(context)
|
||||
context.page_context = {
|
||||
"course": context.course.name,
|
||||
"batch": context.batch,
|
||||
"lesson": context.lesson.name if context.lesson.name else "New Lesson",
|
||||
"is_member": context.membership is not None,
|
||||
}
|
||||
|
||||
|
||||
def get_current_lesson_details(lesson_number, context):
|
||||
details_list = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))
|
||||
details_list = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))
|
||||
|
||||
if not len(details_list):
|
||||
if frappe.form_dict.get("edit"):
|
||||
return None
|
||||
else:
|
||||
redirect_to_lesson(context.course)
|
||||
if not len(details_list):
|
||||
if frappe.form_dict.get("edit"):
|
||||
return None
|
||||
else:
|
||||
redirect_to_lesson(context.course)
|
||||
|
||||
lesson_info = details_list[0]
|
||||
lesson_info.body = lesson_info.body.replace("\"", "'")
|
||||
return lesson_info
|
||||
lesson_info = details_list[0]
|
||||
lesson_info.body = lesson_info.body.replace('"', "'")
|
||||
return lesson_info
|
||||
|
||||
|
||||
def get_url(lesson_number, course):
|
||||
return get_lesson_url(course.name, lesson_number) and get_lesson_url(course.name, lesson_number) + course.query_parameter
|
||||
return (
|
||||
get_lesson_url(course.name, lesson_number)
|
||||
and get_lesson_url(course.name, lesson_number) + course.query_parameter
|
||||
)
|
||||
|
||||
|
||||
def get_page_extensions(context):
|
||||
default_value = ["lms.plugins.PageExtension"]
|
||||
classnames = frappe.get_hooks("lms_lesson_page_extensions") or default_value
|
||||
extensions = [frappe.get_attr(name)() for name in classnames]
|
||||
for e in extensions:
|
||||
e.set_context(context)
|
||||
return extensions
|
||||
default_value = ["lms.plugins.PageExtension"]
|
||||
classnames = frappe.get_hooks("lms_lesson_page_extensions") or default_value
|
||||
extensions = [frappe.get_attr(name)() for name in classnames]
|
||||
for e in extensions:
|
||||
e.set_context(context)
|
||||
return extensions
|
||||
|
||||
|
||||
def get_neighbours(current, lessons):
|
||||
current = flt(current)
|
||||
numbers = sorted(lesson.number for lesson in lessons)
|
||||
index = numbers.index(current)
|
||||
return {
|
||||
"prev": numbers[index-1] if index-1 >= 0 else None,
|
||||
"next": numbers[index+1] if index+1 < len(numbers) else None
|
||||
}
|
||||
current = flt(current)
|
||||
numbers = sorted(lesson.number for lesson in lessons)
|
||||
index = numbers.index(current)
|
||||
return {
|
||||
"prev": numbers[index - 1] if index - 1 >= 0 else None,
|
||||
"next": numbers[index + 1] if index + 1 < len(numbers) else None,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
if(!$(".quiz-card").length) {
|
||||
if (!$(".quiz-card").length) {
|
||||
add_question();
|
||||
}
|
||||
|
||||
@@ -17,52 +16,57 @@ frappe.ready(() => {
|
||||
});
|
||||
|
||||
get_questions();
|
||||
|
||||
});
|
||||
|
||||
|
||||
const add_question = () => {
|
||||
/* if ($(".new-quiz-card").length) {
|
||||
scroll_to_question_container();
|
||||
return;
|
||||
} */
|
||||
|
||||
let add_after = $(".quiz-card").length ? $(".quiz-card:last") : $("#quiz-title");
|
||||
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>
|
||||
<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) => {
|
||||
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");
|
||||
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") }"
|
||||
<div contenteditable="true" data-placeholder="${__(
|
||||
"Option"
|
||||
)}"
|
||||
class="option-input"></div>
|
||||
<div contenteditable="true" data-placeholder="${ __('Explanation') }"
|
||||
<div contenteditable="true" data-placeholder="${__(
|
||||
"Explanation"
|
||||
)}"
|
||||
class="option-input"></div>
|
||||
<div class="option-checkbox">
|
||||
<input type="checkbox">
|
||||
<label class="mb-0"> ${ __("Is Correct") } </label>
|
||||
<label class="mb-0"> ${__("Is Correct")} </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
|
||||
const save_question = (e) => {
|
||||
if (!$("#quiz-title").text()) {
|
||||
frappe.throw(__("Quiz Title is mandatory."));
|
||||
@@ -71,47 +75,54 @@ const save_question = (e) => {
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz",
|
||||
args: {
|
||||
"quiz_title": $("#quiz-title").text(),
|
||||
"questions": get_questions(),
|
||||
"quiz": $("#quiz-title").data("name") || ""
|
||||
quiz_title: $("#quiz-title").text(),
|
||||
questions: get_questions(),
|
||||
quiz: $("#quiz-title").data("name") || "",
|
||||
},
|
||||
callback: (data) => {
|
||||
window.location.href = "/quizzes";
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const get_questions = () => {
|
||||
let questions = [];
|
||||
|
||||
$(".quiz-card").each((i, el) => {
|
||||
if (!$(el).find(".question").text())
|
||||
return;
|
||||
if (!$(el).find(".question").text()) return;
|
||||
|
||||
let details = {};
|
||||
let one_correct_option = false;
|
||||
details["question"] = $(el).find(".question").text();
|
||||
details["question_name"] = $(el).find(".question").data("question") || "";
|
||||
details["question_name"] =
|
||||
$(el).find(".question").data("question") || "";
|
||||
|
||||
Array.from({length: 4}, (x, i) => {
|
||||
Array.from({ length: 4 }, (x, i) => {
|
||||
let num = i + 1;
|
||||
|
||||
details[`option_${num}`] = $(el).find(`.option-${num} .option-input:first`).text();
|
||||
details[`explanation_${num}`] = $(el).find(`.option-${num} .option-input:last`).text();
|
||||
details[`option_${num}`] = $(el)
|
||||
.find(`.option-${num} .option-input:first`)
|
||||
.text();
|
||||
details[`explanation_${num}`] = $(el)
|
||||
.find(`.option-${num} .option-input:last`)
|
||||
.text();
|
||||
|
||||
let is_correct = $(el).find(`.option-${num} .option-checkbox`).find("input").prop("checked");
|
||||
if (is_correct)
|
||||
one_correct_option = true;
|
||||
let is_correct = $(el)
|
||||
.find(`.option-${num} .option-checkbox`)
|
||||
.find("input")
|
||||
.prop("checked");
|
||||
if (is_correct) one_correct_option = true;
|
||||
|
||||
details[`is_correct_${num}`] = is_correct;
|
||||
});
|
||||
|
||||
if (!details["option_1"] || !details["option_2"])
|
||||
frappe.throw(__("Each question must have at least two options."))
|
||||
frappe.throw(__("Each question must have at least two options."));
|
||||
|
||||
if (!one_correct_option)
|
||||
frappe.throw(__("Each question must have at least one correct option."))
|
||||
frappe.throw(
|
||||
__("Each question must have at least one correct option.")
|
||||
);
|
||||
|
||||
questions.push(details);
|
||||
});
|
||||
@@ -119,10 +130,12 @@ const get_questions = () => {
|
||||
return questions;
|
||||
};
|
||||
|
||||
|
||||
const scroll_to_question_container = () => {
|
||||
$([document.documentElement, document.body]).animate({
|
||||
scrollTop: $(".new-quiz-card").offset().top
|
||||
}, 1000);
|
||||
$([document.documentElement, document.body]).animate(
|
||||
{
|
||||
scrollTop: $(".new-quiz-card").offset().top,
|
||||
},
|
||||
1000
|
||||
);
|
||||
$(".new-quiz-card").find(".question").focus();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,20 +3,19 @@ from frappe.utils import cstr
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
quizname = frappe.form_dict["quizname"]
|
||||
if quizname == "new-quiz":
|
||||
context.quiz = frappe._dict()
|
||||
context.quiz.edit_mode = 1
|
||||
else:
|
||||
fields_arr = ["name","question"]
|
||||
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))
|
||||
context.no_cache = 1
|
||||
quizname = frappe.form_dict["quizname"]
|
||||
if quizname == "new-quiz":
|
||||
context.quiz = frappe._dict()
|
||||
context.quiz.edit_mode = 1
|
||||
else:
|
||||
fields_arr = ["name", "question"]
|
||||
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))
|
||||
|
||||
context.quiz = frappe.db.get_value("LMS Quiz", quizname, ["title", "name"], as_dict=1)
|
||||
context.quiz.questions = frappe.get_all("LMS Quiz Question", {
|
||||
"parent": quizname
|
||||
}, fields_arr,
|
||||
order_by="idx")
|
||||
context.quiz = frappe.db.get_value("LMS Quiz", quizname, ["title", "name"], as_dict=1)
|
||||
context.quiz.questions = frappe.get_all(
|
||||
"LMS Quiz Question", {"parent": quizname}, fields_arr, order_by="idx"
|
||||
)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.quiz_list = frappe.get_all("LMS Quiz", {"owner": frappe.session.user}, ["name", "title"])
|
||||
context.no_cache = 1
|
||||
context.quiz_list = frappe.get_all(
|
||||
"LMS Quiz", {"owner": frappe.session.user}, ["name", "title"]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user