ci: flake8 issues

This commit is contained in:
Jannat Patel
2022-11-04 12:43:15 +05:30
parent 33065c0ed3
commit cca42dca49
63 changed files with 12919 additions and 12795 deletions

View File

@@ -9,7 +9,7 @@ root = true
end_of_line = lf end_of_line = lf
insert_final_newline = true insert_final_newline = true
charset = utf-8 charset = utf-8
indent_style = space indent_style = tab
trim_trailing_whitespace = true trim_trailing_whitespace = true
# Python # Python

37
.flake8 Normal file
View File

@@ -0,0 +1,37 @@
[flake8]
ignore =
E121,
E126,
E127,
E128,
E203,
E225,
E226,
E231,
E241,
E251,
E261,
E265,
E302,
E303,
E305,
E402,
E501,
E741,
W291,
W292,
W293,
W391,
W503,
W504,
F403,
B007,
B950,
W191,
E124, # closing bracket, irritating while writing QB code
E131, # continuation line unaligned for hanging indent
E123, # closing bracket does not match indentation of opening bracket's line
E101, # ensured by use of black
max-line-length = 200
exclude=.github/helper/semgrep_rules

74
.github/helper/flake8.conf vendored Normal file
View File

@@ -0,0 +1,74 @@
[flake8]
ignore =
B001,
B007,
B009,
B010,
B950,
E101,
E111,
E114,
E116,
E117,
E121,
E122,
E123,
E124,
E125,
E126,
E127,
E128,
E131,
E201,
E202,
E203,
E211,
E221,
E222,
E223,
E224,
E225,
E226,
E228,
E231,
E241,
E242,
E251,
E261,
E262,
E265,
E266,
E271,
E272,
E273,
E274,
E301,
E302,
E303,
E305,
E306,
E402,
E501,
E502,
E701,
E702,
E703,
E741,
F401,
F403,
F405,
W191,
W291,
W292,
W293,
W391,
W503,
W504,
E711,
E129,
F841,
E713,
E712,
max-line-length = 200

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Job Opportunity", { frappe.ui.form.on("Job Opportunity", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Job Settings", { frappe.ui.form.on("Job Settings", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -1,7 +1,7 @@
frappe.ready(function () { frappe.ready(function () {
frappe.web_form.after_save = () => { frappe.web_form.after_save = () => {
setTimeout(() => { setTimeout(() => {
window.location.href = `/jobs`; window.location.href = `/jobs`;
}); });
}; };
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Certification", { frappe.ui.form.on("Certification", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cohort", { frappe.ui.form.on("Cohort", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cohort Join Request", { frappe.ui.form.on("Cohort Join Request", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cohort Mentor", { frappe.ui.form.on("Cohort Mentor", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cohort Staff", { frappe.ui.form.on("Cohort Staff", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Cohort Subgroup", { frappe.ui.form.on("Cohort Subgroup", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,13 +2,13 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Course Chapter", { frappe.ui.form.on("Course Chapter", {
onload: function (frm) { onload: function (frm) {
frm.set_query("lesson", "lessons", function () { frm.set_query("lesson", "lessons", function () {
return { return {
filters: { filters: {
chapter: frm.doc.name, chapter: frm.doc.name,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,13 +2,13 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Course Evaluator", { frappe.ui.form.on("Course Evaluator", {
onload: (frm) => { onload: (frm) => {
frm.set_query("evaluator", function (doc) { frm.set_query("evaluator", function (doc) {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,20 +2,20 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Course Lesson", { frappe.ui.form.on("Course Lesson", {
setup: function (frm) { setup: function (frm) {
frm.trigger("setup_help"); frm.trigger("setup_help");
}, },
setup_help(frm) { setup_help(frm) {
let quiz_link = `<a href="/app/lms-quiz"> ${__("Quiz List")} </a>`; let quiz_link = `<a href="/app/lms-quiz"> ${__("Quiz List")} </a>`;
let exercise_link = `<a href="/app/exercise"> ${__( let exercise_link = `<a href="/app/exercise"> ${__(
"Exercise List" "Exercise List"
)} </a>`; )} </a>`;
let file_link = `<a href="/app/file"> ${__("File DocType")} </a>`; let file_link = `<a href="/app/file"> ${__("File DocType")} </a>`;
frm.get_field("help").html(` frm.get_field("help").html(`
<p>${__( <p>${__(
"You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same." "You can add some more additional content to the lesson using a special syntax. The table below mentions all types of dynamic content that you can add to the lessons and the syntax for the same."
)}</p> )}</p>
<table class="table"> <table class="table">
<tr style="background-color: var(--fg-hover-color); font-weight: bold"> <tr style="background-color: var(--fg-hover-color); font-weight: bold">
<th style="width: 20%;"> <th style="width: 20%;">
@@ -38,8 +38,8 @@ frappe.ui.form.on("Course Lesson", {
<td> <td>
<span> <span>
${__( ${__(
"Copy and paste the syntax in the editor. Replace 'embed_src' with the embed source that YouTube provides. To get the source, follow the steps mentioned below." "Copy and paste the syntax in the editor. Replace 'embed_src' with the embed source that YouTube provides. To get the source, follow the steps mentioned below."
)} )}
</span> </span>
<ul class="p-4"> <ul class="p-4">
<li> <li>
@@ -47,13 +47,13 @@ frappe.ui.form.on("Course Lesson", {
</li> </li>
<li> <li>
${__( ${__(
"When you share a youtube video, it shows an option called Embed." "When you share a youtube video, it shows an option called Embed."
)} )}
</li> </li>
<li> <li>
${__( ${__(
"On clicking it, it provides an iframe. Copy the source (src) of the iframe and paste it here." "On clicking it, it provides an iframe. Copy the source (src) of the iframe and paste it here."
)} )}
</li> </li>
</ul> </ul>
</td> </td>
@@ -67,9 +67,9 @@ frappe.ui.form.on("Course Lesson", {
</td> </td>
<td> <td>
${__( ${__(
"Copy and paste the syntax in the editor. Replace 'lms_quiz_id' with the ID of the Quiz you want to add. You can get the ID of the quiz from the {0}.", "Copy and paste the syntax in the editor. Replace 'lms_quiz_id' with the ID of the Quiz you want to add. You can get the ID of the quiz from the {0}.",
[quiz_link] [quiz_link]
)} )}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -81,9 +81,9 @@ frappe.ui.form.on("Course Lesson", {
</td> </td>
<td> <td>
${__( ${__(
"Upload a video from your local machine to the {0}. Copy and paste this syntax in the editor. Replace 'url_of_source' with the File URL field of the document you created in the File DocType.", "Upload a video from your local machine to the {0}. Copy and paste this syntax in the editor. Replace 'url_of_source' with the File URL field of the document you created in the File DocType.",
[file_link] [file_link]
)} )}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -95,9 +95,9 @@ frappe.ui.form.on("Course Lesson", {
</td> </td>
<td> <td>
${__( ${__(
"Copy and paste the syntax in the editor. Replace 'exercise_id' with the ID of the Exercise you want to add. You can get the ID of the exercise from the {0}.", "Copy and paste the syntax in the editor. Replace 'exercise_id' with the ID of the Exercise you want to add. You can get the ID of the exercise from the {0}.",
[exercise_link] [exercise_link]
)} )}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -144,5 +144,5 @@ frappe.ui.form.on("Course Lesson", {
</tr> </tr>
</table> </table>
`); `);
}, },
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Exercise", { frappe.ui.form.on("Exercise", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Exercise Latest Submission", { frappe.ui.form.on("Exercise Latest Submission", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Exercise Submission", { frappe.ui.form.on("Exercise Submission", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Function", { frappe.ui.form.on("Function", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Industry", { frappe.ui.form.on("Industry", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Invite Request", { frappe.ui.form.on("Invite Request", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -5,7 +5,7 @@ import unittest
import frappe import frappe
from lms.lms.doctype.invite_request.invite_request import ( from lms.lms.doctype.invite_request.invite_request import (
create_invite_request, update_invite) create_invite_request, update_invite)
class TestInviteRequest(unittest.TestCase): class TestInviteRequest(unittest.TestCase):

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Lesson Assignment", { frappe.ui.form.on("Lesson Assignment", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Batch", { frappe.ui.form.on("LMS Batch", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -6,7 +6,7 @@ from frappe import _
from frappe.model.document import Document from frappe.model.document import Document
from lms.lms.doctype.lms_batch_membership.lms_batch_membership import \ from lms.lms.doctype.lms_batch_membership.lms_batch_membership import \
create_membership create_membership
from lms.lms.utils import is_mentor from lms.lms.utils import is_mentor

View File

@@ -2,13 +2,13 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Batch Membership", { frappe.ui.form.on("LMS Batch Membership", {
onload: function (frm) { onload: function (frm) {
frm.set_query("member", function (doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,20 +2,20 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Certificate", { frappe.ui.form.on("LMS Certificate", {
onload: (frm) => { onload: (frm) => {
frm.set_query("member", function (doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
}, },
refresh: (frm) => { refresh: (frm) => {
if (frm.doc.name) if (frm.doc.name)
frm.add_web_link( frm.add_web_link(
`/courses/${frm.doc.course}/${frm.doc.name}`, `/courses/${frm.doc.course}/${frm.doc.name}`,
"See on Website" "See on Website"
); );
}, },
}); });

View File

@@ -2,33 +2,33 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Certificate Evaluation", { frappe.ui.form.on("LMS Certificate Evaluation", {
refresh: function (frm) { refresh: function (frm) {
if (frm.doc.status == "Pass") { if (frm.doc.status == "Pass") {
frm.add_custom_button(__("Create LMS Certificate"), () => { frm.add_custom_button(__("Create LMS Certificate"), () => {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.create_lms_certificate", method: "lms.lms.doctype.lms_certificate_evaluation.lms_certificate_evaluation.create_lms_certificate",
frm: frm, frm: frm,
}); });
}); });
} }
}, },
onload: function (frm) { onload: function (frm) {
frm.set_query("course", function (doc) { frm.set_query("course", function (doc) {
return { return {
filters: { filters: {
enable_certification: true, enable_certification: true,
grant_certificate_after: "Evaluation", grant_certificate_after: "Evaluation",
}, },
}; };
}); });
frm.set_query("member", function (doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,22 +2,22 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Certificate Request", { frappe.ui.form.on("LMS Certificate Request", {
refresh: function (frm) { refresh: function (frm) {
frm.add_custom_button(__("Create LMS Certificate Evaluation"), () => { frm.add_custom_button(__("Create LMS Certificate Evaluation"), () => {
frappe.model.open_mapped_doc({ frappe.model.open_mapped_doc({
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_lms_certificate_evaluation", method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_lms_certificate_evaluation",
frm: frm, frm: frm,
}); });
}); });
}, },
onload: function (frm) { onload: function (frm) {
frm.set_query("member", function (doc) { frm.set_query("member", function (doc) {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,29 +2,29 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Course", { frappe.ui.form.on("LMS Course", {
onload: function (frm) { onload: function (frm) {
frm.set_query("chapter", "chapters", function () { frm.set_query("chapter", "chapters", function () {
return { return {
filters: { filters: {
course: frm.doc.name, course: frm.doc.name,
}, },
}; };
}); });
frm.set_query("instructor", "instructors", function () { frm.set_query("instructor", "instructors", function () {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
frm.set_query("course", "related_courses", function () { frm.set_query("course", "related_courses", function () {
return { return {
filters: { filters: {
published: true, published: true,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Course Enrollment", { frappe.ui.form.on("LMS Course Enrollment", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Course Interest", { frappe.ui.form.on("LMS Course Interest", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,13 +2,13 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Course Mentor Mapping", { frappe.ui.form.on("LMS Course Mentor Mapping", {
onload: function (frm) { onload: function (frm) {
frm.set_query("mentor", function (doc) { frm.set_query("mentor", function (doc) {
return { return {
filters: { filters: {
ignore_user_type: 1, ignore_user_type: 1,
}, },
}; };
}); });
}, },
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Course Progress", { frappe.ui.form.on("LMS Course Progress", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Course Review", { frappe.ui.form.on("LMS Course Review", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Mentor Request", { frappe.ui.form.on("LMS Mentor Request", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Quiz", { frappe.ui.form.on("LMS Quiz", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Quiz Submission", { frappe.ui.form.on("LMS Quiz Submission", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("LMS Settings", { frappe.ui.form.on("LMS Settings", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Preferred Industry", { frappe.ui.form.on("Preferred Industry", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Related Courses", { frappe.ui.form.on("Related Courses", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Skill", { frappe.ui.form.on("Skill", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -2,6 +2,6 @@
// For license information, please see license.txt // For license information, please see license.txt
frappe.ui.form.on("Skills", { frappe.ui.form.on("Skills", {
// refresh: function(frm) { // refresh: function(frm) {
// } // }
}); });

View File

@@ -1,5 +1,5 @@
"""Handy module to make access to all doctypes from a single place. """Handy module to make access to all doctypes from a single place.
""" """
from .doctype.lms_batch_membership.lms_batch_membership import \ from .doctype.lms_batch_membership.lms_batch_membership import \
LMSBatchMembership as Membership LMSBatchMembership as Membership
from .doctype.lms_course.lms_course import LMSCourse as Course from .doctype.lms_course.lms_course import LMSCourse as Course

View File

@@ -3,13 +3,13 @@
/* eslint-disable */ /* eslint-disable */
frappe.query_reports["Course Progress Summary"] = { frappe.query_reports["Course Progress Summary"] = {
filters: [ filters: [
{ {
fieldname: "course", fieldname: "course",
label: __("Course"), label: __("Course"),
fieldtype: "Link", fieldtype: "Link",
options: "LMS Course", options: "LMS Course",
reqd: 1, reqd: 1,
}, },
], ],
}; };

View File

@@ -5,7 +5,7 @@ import frappe
from frappe import _ from frappe import _
from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result
from frappe.desk.doctype.notification_log.notification_log import \ from frappe.desk.doctype.notification_log.notification_log import \
make_notification_logs make_notification_logs
from frappe.utils import (add_months, cint, cstr, flt, fmt_money, format_date, from frappe.utils import (add_months, cint, cstr, flt, fmt_money, format_date,
get_datetime, getdate) get_datetime, getdate)
from frappe.utils.dateutils import get_period from frappe.utils.dateutils import get_period
@@ -15,7 +15,7 @@ from lms.lms.md import find_macros, markdown_to_html
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+") RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
def slugify(title, used_slugs=[]): def slugify(title, used_slugs):
"""Converts title to a slug. """Converts title to a slug.
If a list of used slugs is specified, it will make sure the generated slug If a list of used slugs is specified, it will make sure the generated slug
@@ -28,6 +28,9 @@ def slugify(title, used_slugs=[]):
>>> slugify("Hello World!", ['hello-world', 'hello-world-2']) >>> slugify("Hello World!", ['hello-world', 'hello-world-2'])
'hello-world-3' 'hello-world-3'
""" """
if not used_slugs:
used_slugs = []
slug = RE_SLUG_NOTALLOWED.sub("-", title.lower()).strip("-") slug = RE_SLUG_NOTALLOWED.sub("-", title.lower()).strip("-")
used_slugs = set(used_slugs) used_slugs = set(used_slugs)

View File

@@ -1,49 +1,49 @@
frappe.ready(function () { frappe.ready(function () {
frappe.web_form.after_save = () => { frappe.web_form.after_save = () => {
let data = frappe.web_form.get_values(); let data = frappe.web_form.get_values();
let slug = new URLSearchParams(window.location.search).get("slug"); let slug = new URLSearchParams(window.location.search).get("slug");
frappe.msgprint({ frappe.msgprint({
message: __("Batch {0} has been successfully created!", [ message: __("Batch {0} has been successfully created!", [
data.title, data.title,
]), ]),
clear: true, clear: true,
}); });
setTimeout(function () { setTimeout(function () {
window.location.href = `courses/${slug}`; window.location.href = `courses/${slug}`;
}, 2000); }, 2000);
}; };
frappe.web_form.validate = () => { frappe.web_form.validate = () => {
let sysdefaults = frappe.boot.sysdefaults; let sysdefaults = frappe.boot.sysdefaults;
let time_format = let time_format =
sysdefaults && sysdefaults.time_format sysdefaults && sysdefaults.time_format
? sysdefaults.time_format ? sysdefaults.time_format
: "HH:mm:ss"; : "HH:mm:ss";
let data = frappe.web_form.get_values(); let data = frappe.web_form.get_values();
data.start_time = moment(data.start_time, time_format).format( data.start_time = moment(data.start_time, time_format).format(
time_format time_format
); );
data.end_time = moment(data.end_time, time_format).format(time_format); data.end_time = moment(data.end_time, time_format).format(time_format);
if (data.start_date < frappe.datetime.nowdate()) { if (data.start_date < frappe.datetime.nowdate()) {
frappe.msgprint(__("Start date cannot be a past date.")); frappe.msgprint(__("Start date cannot be a past date."));
return false; return false;
} }
if ( if (
!frappe.datetime.validate(data.start_time) || !frappe.datetime.validate(data.start_time) ||
!frappe.datetime.validate(data.end_time) !frappe.datetime.validate(data.end_time)
) { ) {
frappe.msgprint(__("Invalid Start or End Time.")); frappe.msgprint(__("Invalid Start or End Time."));
return false; return false;
} }
if (data.start_time > data.end_time) { if (data.start_time > data.end_time) {
frappe.msgprint(__("Start Time should be less than End Time.")); frappe.msgprint(__("Start Time should be less than End Time."));
return false; return false;
} }
return true; return true;
}; };
}); });

View File

@@ -1,96 +1,96 @@
frappe.ready(function () { frappe.ready(function () {
frappe.web_form.after_load = () => { frappe.web_form.after_load = () => {
redirect_to_user_profile_form(); redirect_to_user_profile_form();
add_listener_for_current_company(); add_listener_for_current_company();
add_listener_for_certificate_expiry(); add_listener_for_certificate_expiry();
add_listener_for_skill_add_rows(); add_listener_for_skill_add_rows();
add_listener_for_functions_add_rows(); add_listener_for_functions_add_rows();
add_listener_for_industries_add_rows(); add_listener_for_industries_add_rows();
}; };
frappe.web_form.validate = () => { frappe.web_form.validate = () => {
let information_missing; let information_missing;
const data = frappe.web_form.get_values(); const data = frappe.web_form.get_values();
if (data && data.work_experience && data.work_experience.length) { if (data && data.work_experience && data.work_experience.length) {
data.work_experience.forEach((exp) => { data.work_experience.forEach((exp) => {
if (!exp.current && !exp.to_date) { if (!exp.current && !exp.to_date) {
information_missing = true; information_missing = true;
frappe.msgprint("To Date is mandatory in Work Experience."); frappe.msgprint("To Date is mandatory in Work Experience.");
} }
}); });
} }
if (information_missing) return false; if (information_missing) return false;
return true; return true;
}; };
frappe.web_form.after_save = () => { frappe.web_form.after_save = () => {
setTimeout(() => { setTimeout(() => {
window.location.href = `/profile_/${frappe.web_form.get_value([ window.location.href = `/profile_/${frappe.web_form.get_value([
"username", "username",
])}`; ])}`;
}); });
}; };
}); });
const redirect_to_user_profile_form = () => { const redirect_to_user_profile_form = () => {
if (!frappe.utils.get_url_arg("name")) { if (!frappe.utils.get_url_arg("name")) {
window.location.href = `/edit-profile?name=${frappe.session.user}`; window.location.href = `/edit-profile?name=${frappe.session.user}`;
} }
}; };
const add_listener_for_current_company = () => { const add_listener_for_current_company = () => {
$(document).on("click", "input[data-fieldname='current']", (e) => { $(document).on("click", "input[data-fieldname='current']", (e) => {
if ($(e.currentTarget).prop("checked")) if ($(e.currentTarget).prop("checked"))
$("div[data-fieldname='to_date']").addClass("hide"); $("div[data-fieldname='to_date']").addClass("hide");
else $("div[data-fieldname='to_date']").removeClass("hide"); else $("div[data-fieldname='to_date']").removeClass("hide");
}); });
}; };
const add_listener_for_certificate_expiry = () => { const add_listener_for_certificate_expiry = () => {
$(document).on("click", "input[data-fieldname='expire']", (e) => { $(document).on("click", "input[data-fieldname='expire']", (e) => {
if ($(e.currentTarget).prop("checked")) if ($(e.currentTarget).prop("checked"))
$("div[data-fieldname='expiration_date']").addClass("hide"); $("div[data-fieldname='expiration_date']").addClass("hide");
else $("div[data-fieldname='expiration_date']").removeClass("hide"); else $("div[data-fieldname='expiration_date']").removeClass("hide");
}); });
}; };
const add_listener_for_skill_add_rows = () => { const add_listener_for_skill_add_rows = () => {
$('[data-fieldname="skill"]') $('[data-fieldname="skill"]')
.find(".grid-add-row") .find(".grid-add-row")
.click((e) => { .click((e) => {
if ($('[data-fieldname="skill"]').find(".grid-row").length > 5) { if ($('[data-fieldname="skill"]').find(".grid-row").length > 5) {
$('[data-fieldname="skill"]').find(".grid-add-row").hide(); $('[data-fieldname="skill"]').find(".grid-add-row").hide();
} }
}); });
}; };
const add_listener_for_functions_add_rows = () => { const add_listener_for_functions_add_rows = () => {
$('[data-fieldname="preferred_functions"]') $('[data-fieldname="preferred_functions"]')
.find(".grid-add-row") .find(".grid-add-row")
.click((e) => { .click((e) => {
if ( if (
$('[data-fieldname="preferred_functions"]').find(".grid-row") $('[data-fieldname="preferred_functions"]').find(".grid-row")
.length > 3 .length > 3
) { ) {
$('[data-fieldname="preferred_functions"]') $('[data-fieldname="preferred_functions"]')
.find(".grid-add-row") .find(".grid-add-row")
.hide(); .hide();
} }
}); });
}; };
const add_listener_for_industries_add_rows = () => { const add_listener_for_industries_add_rows = () => {
$('[data-fieldname="preferred_industries"]') $('[data-fieldname="preferred_industries"]')
.find(".grid-add-row") .find(".grid-add-row")
.click((e) => { .click((e) => {
if ( if (
$('[data-fieldname="preferred_industries"]').find(".grid-row") $('[data-fieldname="preferred_industries"]').find(".grid-row")
.length > 3 .length > 3
) { ) {
$('[data-fieldname="preferred_industries"]') $('[data-fieldname="preferred_industries"]')
.find(".grid-add-row") .find(".grid-add-row")
.hide(); .hide();
} }
}); });
}; };

View File

@@ -1,157 +1,157 @@
frappe.ready(() => { frappe.ready(() => {
setup_file_size(); setup_file_size();
$(".join-batch").click((e) => { $(".join-batch").click((e) => {
join_course(e); join_course(e);
}); });
$(".notify-me").click((e) => { $(".notify-me").click((e) => {
notify_user(e); notify_user(e);
}); });
$(".btn-chapter").click((e) => { $(".btn-chapter").click((e) => {
add_chapter(e); add_chapter(e);
}); });
$(document).on("click", ".btn-save-chapter", (e) => { $(document).on("click", ".btn-save-chapter", (e) => {
save_chapter(e); save_chapter(e);
}); });
}); });
const setup_file_size = () => { const setup_file_size = () => {
frappe.provide("frappe.form.formatters"); frappe.provide("frappe.form.formatters");
frappe.form.formatters.FileSize = file_size; frappe.form.formatters.FileSize = file_size;
}; };
const file_size = (value) => { const file_size = (value) => {
if (value > 1048576) { if (value > 1048576) {
value = flt(flt(value) / 1048576, 1) + "M"; value = flt(flt(value) / 1048576, 1) + "M";
} else if (value > 1024) { } else if (value > 1024) {
value = flt(flt(value) / 1024, 1) + "K"; value = flt(flt(value) / 1024, 1) + "K";
} }
return value; return value;
}; };
const join_course = (e) => { const join_course = (e) => {
e.preventDefault(); e.preventDefault();
let course = $(e.currentTarget).attr("data-course"); let course = $(e.currentTarget).attr("data-course");
if (frappe.session.user == "Guest") { if (frappe.session.user == "Guest") {
window.location.href = `/login?redirect-to=/courses/${course}`; window.location.href = `/login?redirect-to=/courses/${course}`;
return; return;
} }
let batch = $(e.currentTarget).attr("data-batch"); let batch = $(e.currentTarget).attr("data-batch");
batch = batch ? decodeURIComponent(batch) : ""; batch = batch ? decodeURIComponent(batch) : "";
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_batch_membership.lms_batch_membership.create_membership", method: "lms.lms.doctype.lms_batch_membership.lms_batch_membership.create_membership",
args: { args: {
batch: batch ? batch : "", batch: batch ? batch : "",
course: course, course: course,
}, },
callback: (data) => { callback: (data) => {
if (data.message == "OK") { if (data.message == "OK") {
$(".no-preview-modal").modal("hide"); $(".no-preview-modal").modal("hide");
frappe.show_alert( frappe.show_alert(
{ {
message: __("Enrolled successfully"), message: __("Enrolled successfully"),
indicator: "green", indicator: "green",
}, },
3 3
); );
setTimeout(function () { setTimeout(function () {
window.location.href = `/courses/${course}/learn/1.1`; window.location.href = `/courses/${course}/learn/1.1`;
}, 1000); }, 1000);
} }
}, },
}); });
}; };
const notify_user = (e) => { const notify_user = (e) => {
e.preventDefault(); e.preventDefault();
var course = decodeURIComponent($(e.currentTarget).attr("data-course")); var course = decodeURIComponent($(e.currentTarget).attr("data-course"));
if (frappe.session.user == "Guest") { if (frappe.session.user == "Guest") {
window.location.href = `/login?redirect-to=/courses/${course}`; window.location.href = `/login?redirect-to=/courses/${course}`;
return; return;
} }
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course_interest.lms_course_interest.capture_interest", method: "lms.lms.doctype.lms_course_interest.lms_course_interest.capture_interest",
args: { args: {
course: course, course: course,
}, },
callback: (data) => { callback: (data) => {
$(".no-preview-modal").modal("hide"); $(".no-preview-modal").modal("hide");
frappe.show_alert( frappe.show_alert(
{ {
message: __( message: __(
"You have opted to be notified for this course. You will receive an email when the course becomes available." "You have opted to be notified for this course. You will receive an email when the course becomes available."
), ),
indicator: "green", indicator: "green",
}, },
3 3
); );
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 3000); }, 3000);
}, },
}); });
}; };
const add_chapter = (e) => { const add_chapter = (e) => {
if ($(".new-chapter").length) { if ($(".new-chapter").length) {
scroll_to_chapter_container(); scroll_to_chapter_container();
return; return;
} }
let next_index = $("[data-index]").last().data("index") + 1 || 1; let next_index = $("[data-index]").last().data("index") + 1 || 1;
let add_after = $(`.chapter-parent:last`).length let add_after = $(`.chapter-parent:last`).length
? $(`.chapter-parent:last`) ? $(`.chapter-parent:last`)
: $("#outline-heading"); : $("#outline-heading");
$(`<div class="chapter-parent chapter-edit new-chapter"> $(`<div class="chapter-parent chapter-edit new-chapter">
<div contenteditable="true" data-placeholder="${__( <div contenteditable="true" data-placeholder="${__(
"Chapter Name" "Chapter Name"
)}" class="chapter-title-main"></div> )}" class="chapter-title-main"></div>
<div class="chapter-description small my-2" contenteditable="true" <div class="chapter-description small my-2" contenteditable="true"
data-placeholder="${__("Short Description")}"></div> data-placeholder="${__("Short Description")}"></div>
<button class="btn btn-sm btn-secondary d-block btn-save-chapter" <button class="btn btn-sm btn-secondary d-block btn-save-chapter"
data-index="${next_index}"> ${__("Save")} </button> data-index="${next_index}"> ${__("Save")} </button>
</div>`).insertAfter(add_after); </div>`).insertAfter(add_after);
scroll_to_chapter_container(); scroll_to_chapter_container();
}; };
const scroll_to_chapter_container = () => { const scroll_to_chapter_container = () => {
$([document.documentElement, document.body]).animate( $([document.documentElement, document.body]).animate(
{ {
scrollTop: $(".new-chapter").offset().top, scrollTop: $(".new-chapter").offset().top,
}, },
1000 1000
); );
$(".new-chapter").find(".chapter-title-main").focus(); $(".new-chapter").find(".chapter-title-main").focus();
}; };
const save_chapter = (e) => { const save_chapter = (e) => {
let target = $(e.currentTarget); let target = $(e.currentTarget);
let parent = target.closest(".chapter-parent"); let parent = target.closest(".chapter-parent");
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.save_chapter", method: "lms.lms.doctype.lms_course.lms_course.save_chapter",
args: { args: {
course: $("#title").data("course"), course: $("#title").data("course"),
title: parent.find(".chapter-title-main").text(), title: parent.find(".chapter-title-main").text(),
chapter_description: parent.find(".chapter-description").text(), chapter_description: parent.find(".chapter-description").text(),
idx: target.data("index"), idx: target.data("index"),
chapter: target.data("chapter") ? target.data("chapter") : "", chapter: target.data("chapter") ? target.data("chapter") : "",
}, },
callback: (data) => { callback: (data) => {
frappe.show_alert({ frappe.show_alert({
message: __("Saved"), message: __("Saved"),
indicator: "green", indicator: "green",
}); });
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 1000); }, 1000);
}, },
}); });
}; };

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,12 @@
function getLiveCodeOptions() { function getLiveCodeOptions() {
var START = ` var START = `
import sketch import sketch
code = open("main.py").read() code = open("main.py").read()
env = dict(sketch.__dict__) env = dict(sketch.__dict__)
exec(code, env) exec(code, env)
`; `;
var SKETCH = ` var SKETCH = `
import json import json
def sendmsg(msgtype, function, args): def sendmsg(msgtype, function, args):
@@ -50,56 +50,56 @@ def clear():
# clear the canvas on start # clear the canvas on start
clear() clear()
`; `;
const CANVAS_FUNCTIONS = { const CANVAS_FUNCTIONS = {
circle: function (ctx, args) { circle: function (ctx, args) {
ctx.beginPath(); ctx.beginPath();
ctx.arc(args.x, args.y, args.d / 2, 0, 2 * Math.PI); ctx.arc(args.x, args.y, args.d / 2, 0, 2 * Math.PI);
ctx.stroke(); ctx.stroke();
}, },
line: function (ctx, args) { line: function (ctx, args) {
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(args.x1, args.y1); ctx.moveTo(args.x1, args.y1);
ctx.lineTo(args.x2, args.y2); ctx.lineTo(args.x2, args.y2);
ctx.stroke(); ctx.stroke();
}, },
rect: function (ctx, args) { rect: function (ctx, args) {
ctx.beginPath(); ctx.beginPath();
ctx.rect(args.x, args.y, args.w, args.h); ctx.rect(args.x, args.y, args.w, args.h);
ctx.stroke(); ctx.stroke();
}, },
clear: function (ctx, args) { clear: function (ctx, args) {
var width = 300; var width = 300;
var height = 300; var height = 300;
ctx.clearRect(0, 0, width, height); ctx.clearRect(0, 0, width, height);
}, },
}; };
function drawOnCanvas(canvasElement, funcName, args) { function drawOnCanvas(canvasElement, funcName, args) {
var ctx = canvasElement.getContext("2d"); var ctx = canvasElement.getContext("2d");
var func = CANVAS_FUNCTIONS[funcName]; var func = CANVAS_FUNCTIONS[funcName];
var scalex = canvasElement.width / 300; var scalex = canvasElement.width / 300;
var scaley = canvasElement.height / 300; var scaley = canvasElement.height / 300;
ctx.save(); ctx.save();
ctx.scale(scalex, scaley); ctx.scale(scalex, scaley);
func(ctx, args); func(ctx, args);
ctx.restore(); ctx.restore();
} }
return { return {
runtime: "python", runtime: "python",
files: [ files: [
{ filename: "start.py", contents: START }, { filename: "start.py", contents: START },
{ filename: "sketch.py", contents: SKETCH }, { filename: "sketch.py", contents: SKETCH },
], ],
command: ["python", "start.py"], command: ["python", "start.py"],
codemirror: true, codemirror: true,
onMessage: { onMessage: {
draw: function (editor, msg) { draw: function (editor, msg) {
const canvasElement = editor.parent.querySelector("canvas"); const canvasElement = editor.parent.querySelector("canvas");
drawOnCanvas(canvasElement, msg.function, msg.args); drawOnCanvas(canvasElement, msg.function, msg.args);
}, },
}, },
}; };
} }

View File

@@ -1,14 +1,14 @@
frappe.ready(() => { frappe.ready(() => {
hide_profile_and_dashboard_for_guest_users(); hide_profile_and_dashboard_for_guest_users();
}); });
const hide_profile_and_dashboard_for_guest_users = () => { const hide_profile_and_dashboard_for_guest_users = () => {
if (frappe.session.user == "Guest") { if (frappe.session.user == "Guest") {
let links = $(".nav-link").filter( let links = $(".nav-link").filter(
(i, elem) => (i, elem) =>
$(elem).text().trim() === "My Profile" || $(elem).text().trim() === "My Profile" ||
$(elem).text().trim() === "Dashboard" $(elem).text().trim() === "Dashboard"
); );
links.length && links.each((i, elem) => $(elem).addClass("hide")); links.length && links.each((i, elem) => $(elem).addClass("hide"));
} }
}; };

View File

@@ -1,74 +1,74 @@
frappe.ready(() => { frappe.ready(() => {
$("#search-course").keyup((e) => { $("#search-course").keyup((e) => {
search_course(e); search_course(e);
}); });
$(".close-search-empty-state").click((e) => { $(".close-search-empty-state").click((e) => {
close_search_empty_state(e); close_search_empty_state(e);
}); });
}); });
const search_course = (e) => { const search_course = (e) => {
let input = $(e.currentTarget).val(); let input = $(e.currentTarget).val();
if (input == window.input) return; if (input == window.input) return;
window.input = input; window.input = input;
if (input.length < 3 || input.trim() == "") { if (input.length < 3 || input.trim() == "") {
$(".course-card").removeClass("hide"); $(".course-card").removeClass("hide");
$(".search-empty-state").addClass("hide"); $(".search-empty-state").addClass("hide");
fix_heading_styles(); fix_heading_styles();
return; return;
} }
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.search_course", method: "lms.lms.doctype.lms_course.lms_course.search_course",
args: { args: {
text: input, text: input,
}, },
callback: (data) => { callback: (data) => {
render_course_list(data.message); render_course_list(data.message);
}, },
}); });
}; };
const render_course_list = (courses) => { const render_course_list = (courses) => {
fix_heading_styles(); fix_heading_styles();
$(".search-empty-state").addClass("hide"); $(".search-empty-state").addClass("hide");
if (!courses.length) { if (!courses.length) {
$(".course-card").removeClass("hide"); $(".course-card").removeClass("hide");
$(".search-empty-state").removeClass("hide"); $(".search-empty-state").removeClass("hide");
return; return;
} }
$(".course-card").addClass("hide"); $(".course-card").addClass("hide");
for (course in courses) { for (course in courses) {
$("[data-course=" + courses[course].name + "]").removeClass("hide"); $("[data-course=" + courses[course].name + "]").removeClass("hide");
} }
const visible_live_courses = $(".live-courses .course-card").not(".hide"); const visible_live_courses = $(".live-courses .course-card").not(".hide");
const visible_upcoming_courses = $(".upcoming-courses .course-card").not( const visible_upcoming_courses = $(".upcoming-courses .course-card").not(
".hide" ".hide"
); );
if (!visible_live_courses.length) { if (!visible_live_courses.length) {
$(".live-courses .course-home-headings").addClass("hide"); $(".live-courses .course-home-headings").addClass("hide");
$(".upcoming-courses").removeClass("mt-10"); $(".upcoming-courses").removeClass("mt-10");
} }
if (!visible_upcoming_courses.length) { if (!visible_upcoming_courses.length) {
$(".upcoming-courses .course-home-headings").addClass("hide"); $(".upcoming-courses .course-home-headings").addClass("hide");
} }
}; };
const fix_heading_styles = () => { const fix_heading_styles = () => {
$(".course-home-headings").removeClass("hide"); $(".course-home-headings").removeClass("hide");
$(".upcoming-courses").addClass("mt-10"); $(".upcoming-courses").addClass("mt-10");
}; };
const close_search_empty_state = (e) => { const close_search_empty_state = (e) => {
$(".search-empty-state").addClass("hide"); $(".search-empty-state").addClass("hide");
$("#search-course").val(""); $("#search-course").val("");
}; };

View File

@@ -56,7 +56,10 @@ class Widget:
'<div>Hello, World!</div>' '<div>Hello, World!</div>'
""" """
def __init__(self, name, widget_globals={}): def __init__(self, name, widget_globals):
if not widget_globals:
widget_globals = {}
self.widget_globals = widget_globals self.widget_globals = widget_globals
self.name = name self.name = name

View File

@@ -1,517 +1,517 @@
frappe.ready(() => { frappe.ready(() => {
this.marked_as_complete = false; this.marked_as_complete = false;
this.quiz_submitted = false; this.quiz_submitted = false;
this.file_type; this.file_type;
let self = this; let self = this;
localStorage.removeItem($("#quiz-title").data("name")); localStorage.removeItem($("#quiz-title").data("name"));
fetch_assignments(); fetch_assignments();
save_current_lesson(); save_current_lesson();
set_file_type(); set_file_type();
$(".option").click((e) => { $(".option").click((e) => {
enable_check(e); enable_check(e);
}); });
$(window).scroll(() => { $(window).scroll(() => {
let self = this; let self = this;
if ( if (
!$("#status-indicator").length && !$("#status-indicator").length &&
!self.marked_as_complete && !self.marked_as_complete &&
$(".title").hasClass("is-member") $(".title").hasClass("is-member")
) { ) {
self.marked_as_complete = true; self.marked_as_complete = true;
mark_progress(); mark_progress();
} }
}); });
$("#summary").click((e) => { $("#summary").click((e) => {
quiz_summary(e); quiz_summary(e);
}); });
$("#check").click((e) => { $("#check").click((e) => {
check_answer(e); check_answer(e);
}); });
$("#next").click((e) => { $("#next").click((e) => {
mark_active_question(e); mark_active_question(e);
}); });
$("#try-again").click((e) => { $("#try-again").click((e) => {
try_quiz_again(e); try_quiz_again(e);
}); });
$("#certification").click((e) => { $("#certification").click((e) => {
create_certificate(e); create_certificate(e);
}); });
$(".submit-work").click((e) => { $(".submit-work").click((e) => {
attach_work(e); attach_work(e);
}); });
$(".clear-work").click((e) => { $(".clear-work").click((e) => {
clear_work(e); clear_work(e);
}); });
$(".btn-lesson").click((e) => { $(".btn-lesson").click((e) => {
save_lesson(e); save_lesson(e);
}); });
$(".add-attachment").click((e) => { $(".add-attachment").click((e) => {
show_upload_modal(); show_upload_modal();
}); });
$(".btn-start-quiz").click((e) => { $(".btn-start-quiz").click((e) => {
$("#start-banner").addClass("hide"); $("#start-banner").addClass("hide");
$("#quiz-form").removeClass("hide"); $("#quiz-form").removeClass("hide");
mark_active_question(); mark_active_question();
}); });
$(".btn-edit").click((e) => { $(".btn-edit").click((e) => {
window.location.href = `${window.location.href}?edit=1`; window.location.href = `${window.location.href}?edit=1`;
}); });
$(".btn-back").click((e) => { $(".btn-back").click((e) => {
window.location.href = window.location.href.split("?")[0]; window.location.href = window.location.href.split("?")[0];
}); });
$(document).on("click", ".copy-link", (e) => { $(document).on("click", ".copy-link", (e) => {
frappe.utils.copy_to_clipboard($(e.currentTarget).data("link")); frappe.utils.copy_to_clipboard($(e.currentTarget).data("link"));
$(".attachments").collapse("hide"); $(".attachments").collapse("hide");
}); });
if ($("#quiz-title").data("max-attempts")) { if ($("#quiz-title").data("max-attempts")) {
window.addEventListener("beforeunload", (e) => { window.addEventListener("beforeunload", (e) => {
e.returnValue = ""; e.returnValue = "";
if ($(".active-question").length && !self.quiz_submitted) { if ($(".active-question").length && !self.quiz_submitted) {
quiz_summary(); quiz_summary();
} }
}); });
} }
if ($("#body").length) { if ($("#body").length) {
make_editor(); make_editor();
} }
$("#file-type").change((e) => { $("#file-type").change((e) => {
$("#file-type option:selected").each(function () { $("#file-type option:selected").each(function () {
self.file_type = $(this).val(); self.file_type = $(this).val();
}); });
}); });
}); });
const save_current_lesson = () => { const save_current_lesson = () => {
if ($(".title").hasClass("is-member")) { if ($(".title").hasClass("is-member")) {
frappe.call("lms.lms.api.save_current_lesson", { frappe.call("lms.lms.api.save_current_lesson", {
course_name: $(".title").attr("data-course"), course_name: $(".title").attr("data-course"),
lesson_name: $(".title").attr("data-lesson"), lesson_name: $(".title").attr("data-lesson"),
}); });
} }
}; };
const enable_check = (e) => { const enable_check = (e) => {
if ($(".option:checked").length) { if ($(".option:checked").length) {
$("#check").removeAttr("disabled"); $("#check").removeAttr("disabled");
$(".custom-checkbox").removeClass("active-option"); $(".custom-checkbox").removeClass("active-option");
$(".option:checked") $(".option:checked")
.closest(".custom-checkbox") .closest(".custom-checkbox")
.addClass("active-option"); .addClass("active-option");
} }
}; };
const mark_active_question = (e = undefined) => { const mark_active_question = (e = undefined) => {
$(".timer").addClass("hide"); $(".timer").addClass("hide");
calculate_and_display_time(100); calculate_and_display_time(100);
$(".timer").removeClass("hide"); $(".timer").removeClass("hide");
let current_index = $(".active-question").attr("data-qt-index") || 0; let current_index = $(".active-question").attr("data-qt-index") || 0;
let next_index = parseInt(current_index) + 1; let next_index = parseInt(current_index) + 1;
$(".question").addClass("hide").removeClass("active-question"); $(".question").addClass("hide").removeClass("active-question");
$(`.question[data-qt-index='${next_index}']`) $(`.question[data-qt-index='${next_index}']`)
.removeClass("hide") .removeClass("hide")
.addClass("active-question"); .addClass("active-question");
$(".current-question").text(`${next_index}`); $(".current-question").text(`${next_index}`);
$("#check").removeClass("hide").attr("disabled", true); $("#check").removeClass("hide").attr("disabled", true);
$("#next").addClass("hide"); $("#next").addClass("hide");
$(".explanation").addClass("hide"); $(".explanation").addClass("hide");
initialize_timer(); initialize_timer();
}; };
const mark_progress = () => { const mark_progress = () => {
let status = "Complete"; let status = "Complete";
frappe.call({ frappe.call({
method: "lms.lms.doctype.course_lesson.course_lesson.save_progress", method: "lms.lms.doctype.course_lesson.course_lesson.save_progress",
args: { args: {
lesson: $(".title").attr("data-lesson"), lesson: $(".title").attr("data-lesson"),
course: $(".title").attr("data-course"), course: $(".title").attr("data-course"),
status: status, status: status,
}, },
callback: (data) => { callback: (data) => {
change_progress_indicators(); change_progress_indicators();
show_certificate_if_course_completed(data); show_certificate_if_course_completed(data);
}, },
}); });
}; };
const change_progress_indicators = () => { const change_progress_indicators = () => {
$(".active-lesson .lesson-progress-tick").removeClass("hide"); $(".active-lesson .lesson-progress-tick").removeClass("hide");
}; };
const show_certificate_if_course_completed = (data) => { const show_certificate_if_course_completed = (data) => {
if ( if (
data.message == 100 && data.message == 100 &&
!$(".next").length && !$(".next").length &&
$("#certification").hasClass("hide") $("#certification").hasClass("hide")
) { ) {
$("#certification").removeClass("hide"); $("#certification").removeClass("hide");
} }
}; };
const quiz_summary = (e = undefined) => { const quiz_summary = (e = undefined) => {
e && e.preventDefault(); e && e.preventDefault();
let quiz_name = $("#quiz-title").data("name"); let quiz_name = $("#quiz-title").data("name");
let total_questions = $(".question").length; let total_questions = $(".question").length;
let self = this; let self = this;
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary", method: "lms.lms.doctype.lms_quiz.lms_quiz.quiz_summary",
args: { args: {
quiz: quiz_name, quiz: quiz_name,
results: localStorage.getItem(quiz_name), results: localStorage.getItem(quiz_name),
}, },
callback: (data) => { callback: (data) => {
let message = let message =
data.message == total_questions data.message == total_questions
? __("Excellent Work 👏") ? __("Excellent Work 👏")
: __("Better luck next time"); : __("Better luck next time");
$(".question").addClass("hide"); $(".question").addClass("hide");
$("#summary").addClass("hide"); $("#summary").addClass("hide");
$("#quiz-form") $("#quiz-form")
.parent() .parent()
.prepend( .prepend(
`<div class="text-center summary"> `<div class="text-center summary">
<h2> ${message} </h2> <h2> ${message} </h2>
<div class="font-weight-bold"> ${data.message}/${total_questions} </div> <div class="font-weight-bold"> ${data.message}/${total_questions} </div>
</div>` </div>`
); );
$("#try-again").removeClass("hide"); $("#try-again").removeClass("hide");
self.quiz_submitted = true; self.quiz_submitted = true;
}, },
}); });
}; };
const try_quiz_again = (e) => { const try_quiz_again = (e) => {
window.location.reload(); window.location.reload();
}; };
const check_answer = (e = undefined) => { const check_answer = (e = undefined) => {
e && e.preventDefault(); e && e.preventDefault();
clearInterval(self.timer); clearInterval(self.timer);
$(".timer").addClass("hide"); $(".timer").addClass("hide");
let total_questions = $(".question").length; let total_questions = $(".question").length;
let current_index = $(".active-question").attr("data-qt-index"); let current_index = $(".active-question").attr("data-qt-index");
$(".explanation").removeClass("hide"); $(".explanation").removeClass("hide");
$("#check").addClass("hide"); $("#check").addClass("hide");
if (current_index == total_questions) { if (current_index == total_questions) {
if ($(".eligible-for-submission").length) { if ($(".eligible-for-submission").length) {
$("#summary").removeClass("hide"); $("#summary").removeClass("hide");
} else { } else {
$("#submission-message").removeClass("hide"); $("#submission-message").removeClass("hide");
} }
} else { } else {
$("#next").removeClass("hide"); $("#next").removeClass("hide");
} }
let [answer, is_correct] = parse_options(); let [answer, is_correct] = parse_options();
add_to_local_storage(current_index, answer, is_correct); add_to_local_storage(current_index, answer, is_correct);
}; };
const parse_options = () => { const parse_options = () => {
let answer = []; let answer = [];
let is_correct = []; let is_correct = [];
$(".active-question input").each((i, element) => { $(".active-question input").each((i, element) => {
let correct = parseInt($(element).attr("data-correct")); let correct = parseInt($(element).attr("data-correct"));
if ($(element).prop("checked")) { if ($(element).prop("checked")) {
answer.push(decodeURIComponent($(element).val())); answer.push(decodeURIComponent($(element).val()));
correct && is_correct.push(1); correct && is_correct.push(1);
correct ? add_icon(element, "check") : add_icon(element, "wrong"); correct ? add_icon(element, "check") : add_icon(element, "wrong");
} else { } else {
correct && is_correct.push(0); correct && is_correct.push(0);
correct correct
? add_icon(element, "minus-circle-green") ? add_icon(element, "minus-circle-green")
: add_icon(element, "minus-circle"); : add_icon(element, "minus-circle");
} }
}); });
return [answer, is_correct]; return [answer, is_correct];
}; };
const add_icon = (element, icon) => { const add_icon = (element, icon) => {
$(element).closest(".custom-checkbox").removeClass("active-option"); $(element).closest(".custom-checkbox").removeClass("active-option");
let label = $(element).siblings(".option-text").text(); let label = $(element).siblings(".option-text").text();
$(element).siblings(".option-text").html(` $(element).siblings(".option-text").html(`
<div> <div>
<img class="d-inline mr-3" src="/assets/lms/icons/${icon}.svg"> <img class="d-inline mr-3" src="/assets/lms/icons/${icon}.svg">
${label} ${label}
</div> </div>
`); `);
//$(element).parent().empty().html(`<div class="option-text"><img class="mr-3" src="/assets/lms/icons/${icon}.svg"> ${label}</div>`); //$(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) => { 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_stored = JSON.parse(localStorage.getItem(quiz_name));
let quiz_obj = { let quiz_obj = {
question_index: current_index, question_index: current_index,
answer: answer.join(), answer: answer.join(),
is_correct: is_correct, is_correct: is_correct,
}; };
quiz_stored ? quiz_stored.push(quiz_obj) : (quiz_stored = [quiz_obj]); quiz_stored ? quiz_stored.push(quiz_obj) : (quiz_stored = [quiz_obj]);
localStorage.setItem(quiz_name, JSON.stringify(quiz_stored)); localStorage.setItem(quiz_name, JSON.stringify(quiz_stored));
}; };
const create_certificate = (e) => { const create_certificate = (e) => {
e.preventDefault(); e.preventDefault();
course = $(".title").attr("data-course"); course = $(".title").attr("data-course");
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate", method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
args: { args: {
course: course, course: course,
}, },
callback: (data) => { callback: (data) => {
window.location.href = `/courses/${course}/${data.message.name}`; window.location.href = `/courses/${course}/${data.message.name}`;
}, },
}); });
}; };
const attach_work = (e) => { const attach_work = (e) => {
const target = $(e.currentTarget); const target = $(e.currentTarget);
let files = target.siblings(".attach-file").prop("files"); let files = target.siblings(".attach-file").prop("files");
if (files && files.length) { if (files && files.length) {
files = add_files(files); files = add_files(files);
return_as_dataurl(files); return_as_dataurl(files);
files.map((file) => { files.map((file) => {
upload_file(file, target); upload_file(file, target);
}); });
} }
}; };
const upload_file = (file, target) => { const upload_file = (file, target) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => { xhr.onreadystatechange = () => {
if (xhr.readyState == XMLHttpRequest.DONE) { if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status === 200) { if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText); let response = JSON.parse(xhr.responseText);
create_lesson_work(response.message, target); create_lesson_work(response.message, target);
} else if (xhr.status === 403) { } else if (xhr.status === 403) {
let response = JSON.parse(xhr.responseText); let response = JSON.parse(xhr.responseText);
frappe.msgprint( frappe.msgprint(
`Not permitted. ${response._error_message || ""}` `Not permitted. ${response._error_message || ""}`
); );
} else if (xhr.status === 413) { } else if (xhr.status === 413) {
frappe.msgprint( frappe.msgprint(
"Size exceeds the maximum allowed file size." "Size exceeds the maximum allowed file size."
); );
} else { } else {
frappe.msgprint( frappe.msgprint(
xhr.status === 0 xhr.status === 0
? "XMLHttpRequest Error" ? "XMLHttpRequest Error"
: `${xhr.status} : ${xhr.statusText}` : `${xhr.status} : ${xhr.statusText}`
); );
} }
} }
}; };
xhr.open("POST", "/api/method/upload_file", true); xhr.open("POST", "/api/method/upload_file", true);
xhr.setRequestHeader("Accept", "application/json"); xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token); xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token);
let form_data = new FormData(); let form_data = new FormData();
if (file.file_obj) { 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); xhr.send(form_data);
}); });
}; };
const create_lesson_work = (file, target) => { const create_lesson_work = (file, target) => {
frappe.call({ frappe.call({
method: "lms.lms.doctype.lesson_assignment.lesson_assignment.upload_assignment", method: "lms.lms.doctype.lesson_assignment.lesson_assignment.upload_assignment",
args: { args: {
assignment: file.file_url, assignment: file.file_url,
lesson: $(".title").attr("data-lesson"), lesson: $(".title").attr("data-lesson"),
}, },
callback: (data) => { callback: (data) => {
target.siblings(".attach-file").addClass("hide"); target.siblings(".attach-file").addClass("hide");
target.siblings(".preview-work").removeClass("hide"); target.siblings(".preview-work").removeClass("hide");
target target
.siblings(".preview-work") .siblings(".preview-work")
.find("a") .find("a")
.attr("href", file.file_url) .attr("href", file.file_url)
.text(file.file_name); .text(file.file_name);
target.addClass("hide"); target.addClass("hide");
}, },
}); });
}; };
const return_as_dataurl = (files) => { const return_as_dataurl = (files) => {
let promises = files.map((file) => let promises = files.map((file) =>
frappe.dom.file_to_base64(file.file_obj).then((dataurl) => { frappe.dom.file_to_base64(file.file_obj).then((dataurl) => {
file.dataurl = dataurl; file.dataurl = dataurl;
this.on_success && this.on_success(file); this.on_success && this.on_success(file);
}) })
); );
return Promise.all(promises); return Promise.all(promises);
}; };
const add_files = (files) => { const add_files = (files) => {
files = Array.from(files).map((file) => { files = Array.from(files).map((file) => {
let is_image = file.type.startsWith("image"); let is_image = file.type.startsWith("image");
return { return {
file_obj: file, file_obj: file,
cropper_file: file, cropper_file: file,
crop_box_data: null, crop_box_data: null,
optimize: this.attach_doc_image ? true : false, optimize: this.attach_doc_image ? true : false,
name: file.name, name: file.name,
doc: null, doc: null,
progress: 0, progress: 0,
total: 0, total: 0,
failed: false, failed: false,
request_succeeded: false, request_succeeded: false,
error_message: null, error_message: null,
uploading: false, uploading: false,
private: !is_image, private: !is_image,
}; };
}); });
return files; return files;
}; };
const clear_work = (e) => { const clear_work = (e) => {
const target = $(e.currentTarget); const target = $(e.currentTarget);
const parent = target.closest(".preview-work"); const parent = target.closest(".preview-work");
parent.addClass("hide"); parent.addClass("hide");
parent.siblings(".attach-file").removeClass("hide").val(null); parent.siblings(".attach-file").removeClass("hide").val(null);
parent.siblings(".submit-work").removeClass("hide"); parent.siblings(".submit-work").removeClass("hide");
}; };
const fetch_assignments = () => { const fetch_assignments = () => {
if ($(".attach-file").length <= 0) return; if ($(".attach-file").length <= 0) return;
frappe.call({ frappe.call({
method: "lms.lms.doctype.lesson_assignment.lesson_assignment.get_assignment", method: "lms.lms.doctype.lesson_assignment.lesson_assignment.get_assignment",
args: { args: {
lesson: $(".title").attr("data-lesson"), lesson: $(".title").attr("data-lesson"),
}, },
callback: (data) => { callback: (data) => {
if (data.message) { if (data.message) {
const assignment = data.message; const assignment = data.message;
let target = $(".attach-file"); let target = $(".attach-file");
target.addClass("hide"); target.addClass("hide");
target.siblings(".submit-work").addClass("hide"); target.siblings(".submit-work").addClass("hide");
target.siblings(".preview-work").removeClass("hide"); target.siblings(".preview-work").removeClass("hide");
target target
.siblings(".preview-work") .siblings(".preview-work")
.find("a") .find("a")
.attr("href", assignment.assignment) .attr("href", assignment.assignment)
.text(assignment.file_name); .text(assignment.file_name);
} }
}, },
}); });
}; };
const initialize_timer = () => { const initialize_timer = () => {
this.time_left = $(".timer").data("time"); this.time_left = $(".timer").data("time");
calculate_and_display_time(100, this.time_left); calculate_and_display_time(100, this.time_left);
$(".timer").removeClass("hide"); $(".timer").removeClass("hide");
const total_time = $(".timer").data("time"); const total_time = $(".timer").data("time");
this.start_time = new Date().getTime(); this.start_time = new Date().getTime();
const self = this; const self = this;
let old_diff; let old_diff;
this.timer = setInterval(function () { 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; var variation = old_diff ? diff - old_diff : diff;
old_diff = diff; old_diff = diff;
self.time_left -= variation; self.time_left -= variation;
let percent_time = (self.time_left / total_time) * 100; let percent_time = (self.time_left / total_time) * 100;
calculate_and_display_time(percent_time); calculate_and_display_time(percent_time);
if (self.time_left <= 0) { if (self.time_left <= 0) {
clearInterval(self.timer); clearInterval(self.timer);
$(".timer").addClass("hide"); $(".timer").addClass("hide");
check_answer(); check_answer();
} }
}, 100); }, 100);
}; };
const calculate_and_display_time = (percent_time) => { const calculate_and_display_time = (percent_time) => {
$(".timer .progress-bar").attr("aria-valuenow", percent_time); $(".timer .progress-bar").attr("aria-valuenow", percent_time);
$(".timer .progress-bar").attr("aria-valuemax", percent_time); $(".timer .progress-bar").attr("aria-valuemax", percent_time);
$(".timer .progress-bar").css("width", `${percent_time}%`); $(".timer .progress-bar").css("width", `${percent_time}%`);
let progress_color = percent_time < 20 ? "red" : "var(--primary-color)"; let progress_color = percent_time < 20 ? "red" : "var(--primary-color)";
$(".timer .progress-bar").css("background-color", progress_color); $(".timer .progress-bar").css("background-color", progress_color);
}; };
const save_lesson = (e) => { const save_lesson = (e) => {
let lesson = $("#title").data("lesson"); let lesson = $("#title").data("lesson");
let self = this; let self = this;
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.save_lesson", method: "lms.lms.doctype.lms_course.lms_course.save_lesson",
args: { args: {
title: $("#title").text(), title: $("#title").text(),
body: this.code_field_group.fields_dict["code_md"].value, body: this.code_field_group.fields_dict["code_md"].value,
youtube: $("#youtube").text(), youtube: $("#youtube").text(),
quiz_id: $("#quiz-id").text(), quiz_id: $("#quiz-id").text(),
chapter: $("#title").data("chapter"), chapter: $("#title").data("chapter"),
preview: $("#preview").prop("checked") ? 1 : 0, preview: $("#preview").prop("checked") ? 1 : 0,
idx: $("#title").data("index"), idx: $("#title").data("index"),
lesson: lesson ? lesson : "", lesson: lesson ? lesson : "",
question: $("#assignment-question").text(), question: $("#assignment-question").text(),
file_type: self.file_type, file_type: self.file_type,
}, },
callback: (data) => { callback: (data) => {
frappe.show_alert({ frappe.show_alert({
message: __("Saved"), message: __("Saved"),
indicator: "green", indicator: "green",
}); });
setTimeout(() => { setTimeout(() => {
window.location.href = window.location.href.split("?")[0]; window.location.href = window.location.href.split("?")[0];
}, 1000); }, 1000);
}, },
}); });
}; };
const show_upload_modal = () => { const show_upload_modal = () => {
new frappe.ui.FileUploader({ new frappe.ui.FileUploader({
folder: "Home/Attachments", folder: "Home/Attachments",
restrictions: { restrictions: {
allowed_file_types: ["image/*", "video/*"], allowed_file_types: ["image/*", "video/*"],
}, },
on_success: (file_doc) => { on_success: (file_doc) => {
$(".attachments").append(build_attachment_table(file_doc)); $(".attachments").append(build_attachment_table(file_doc));
let count = $(".attachment-count").data("count") + 1; let count = $(".attachment-count").data("count") + 1;
$(".attachment-count").data("count", count); $(".attachment-count").data("count", count);
$(".attachment-count").html(__(`${count} attachments`)); $(".attachment-count").html(__(`${count} attachments`));
$(".attachments").removeClass("hide"); $(".attachments").removeClass("hide");
}, },
}); });
}; };
const build_attachment_table = (file_doc) => { const build_attachment_table = (file_doc) => {
let video_types = ["mov", "mp4", "mkv"]; 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 is_video = video_types.indexOf(video_extension) >= 0;
let link = is_video let link = is_video
? `{{ Video('${file_doc.file_url}') }}` ? `{{ Video('${file_doc.file_url}') }}`
: `![](${file_doc.file_url})`; : `![](${file_doc.file_url})`;
return $(` return $(`
<tr class="attachment-row"> <tr class="attachment-row">
<td>${file_doc.file_name}</td> <td>${file_doc.file_name}</td>
<td class=""> <td class="">
@@ -524,36 +524,36 @@ const build_attachment_table = (file_doc) => {
}; };
const make_editor = () => { const make_editor = () => {
this.code_field_group = new frappe.ui.FieldGroup({ this.code_field_group = new frappe.ui.FieldGroup({
fields: [ fields: [
{ {
fieldname: "code_md", fieldname: "code_md",
fieldtype: "Code", fieldtype: "Code",
options: "Markdown", options: "Markdown",
wrap: true, wrap: true,
max_lines: Infinity, max_lines: Infinity,
min_lines: 20, min_lines: 20,
default: $("#body").data("body"), default: $("#body").data("body"),
depends_on: 'eval:doc.type=="Markdown"', depends_on: 'eval:doc.type=="Markdown"',
}, },
], ],
body: $("#body").get(0), body: $("#body").get(0),
}); });
this.code_field_group.make(); this.code_field_group.make();
$("#body .form-section:last").removeClass("empty-section"); $("#body .form-section:last").removeClass("empty-section");
$("#body .frappe-control").removeClass("hide-control"); $("#body .frappe-control").removeClass("hide-control");
$("#body .form-column").addClass("p-0"); $("#body .form-column").addClass("p-0");
}; };
const set_file_type = () => { const set_file_type = () => {
let self = this; let self = this;
let file_type = $("#file-type").data("type"); let file_type = $("#file-type").data("type");
if (file_type) { if (file_type) {
$("#file-type option").each((i, elem) => { $("#file-type option").each((i, elem) => {
if ($(elem).val() == file_type) { if ($(elem).val() == file_type) {
$(elem).attr("selected", true); $(elem).attr("selected", true);
self.file_type = file_type; self.file_type = file_type;
} }
}); });
} }
}; };

View File

@@ -1,63 +1,63 @@
frappe.ready(() => { frappe.ready(() => {
if (!$(".quiz-card").length) { if (!$(".quiz-card").length) {
add_question(); add_question();
} }
$(".btn-question").click((e) => { $(".btn-question").click((e) => {
add_question(); add_question();
}); });
$(".btn-save-question").click((e) => { $(".btn-save-question").click((e) => {
save_question(e); save_question(e);
}); });
$(".copy-quiz-id").click((e) => { $(".copy-quiz-id").click((e) => {
frappe.utils.copy_to_clipboard($(e.currentTarget).data("name")); frappe.utils.copy_to_clipboard($(e.currentTarget).data("name"));
}); });
get_questions(); get_questions();
}); });
const add_question = () => { const add_question = () => {
/* if ($(".new-quiz-card").length) { /* if ($(".new-quiz-card").length) {
scroll_to_question_container(); scroll_to_question_container();
return; return;
} */ } */
let add_after = $(".quiz-card").length let add_after = $(".quiz-card").length
? $(".quiz-card:last") ? $(".quiz-card:last")
: $("#quiz-title"); : $("#quiz-title");
let question_template = `<div class="quiz-card new-quiz-card"> let question_template = `<div class="quiz-card new-quiz-card">
<div contenteditable="true" data-placeholder="${__( <div contenteditable="true" data-placeholder="${__(
"Question" "Question"
)}" class="question mb-4"></div> )}" class="question mb-4"></div>
</div>`; </div>`;
$(question_template).insertAfter(add_after); $(question_template).insertAfter(add_after);
get_question_template(); get_question_template();
$(".btn-save-question").removeClass("hide"); $(".btn-save-question").removeClass("hide");
}; };
const get_question_template = () => { 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 option_template = get_option_template(num + 1);
let add_after = $(".quiz-card:last .option-group").length let add_after = $(".quiz-card:last .option-group").length
? $(".quiz-card:last .option-group").last() ? $(".quiz-card:last .option-group").last()
: $(".question:last"); : $(".question:last");
question_template = $(option_template).insertAfter(add_after); question_template = $(option_template).insertAfter(add_after);
}); });
}; };
const get_option_template = (num) => { const get_option_template = (num) => {
return `<div class="option-group mt-4"> return `<div class="option-group mt-4">
<label class="">${__("Option")} ${num}</label> <label class="">${__("Option")} ${num}</label>
<div class="d-flex justify-content-between option-${num}"> <div class="d-flex justify-content-between option-${num}">
<div contenteditable="true" data-placeholder="${__( <div contenteditable="true" data-placeholder="${__(
"Option" "Option"
)}" )}"
class="option-input"></div> class="option-input"></div>
<div contenteditable="true" data-placeholder="${__( <div contenteditable="true" data-placeholder="${__(
"Explanation" "Explanation"
)}" )}"
class="option-input"></div> class="option-input"></div>
<div class="option-checkbox"> <div class="option-checkbox">
<input type="checkbox"> <input type="checkbox">
@@ -68,74 +68,74 @@ const get_option_template = (num) => {
}; };
const save_question = (e) => { const save_question = (e) => {
if (!$("#quiz-title").text()) { if (!$("#quiz-title").text()) {
frappe.throw(__("Quiz Title is mandatory.")); frappe.throw(__("Quiz Title is mandatory."));
} }
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz", method: "lms.lms.doctype.lms_quiz.lms_quiz.save_quiz",
args: { args: {
quiz_title: $("#quiz-title").text(), quiz_title: $("#quiz-title").text(),
questions: get_questions(), questions: get_questions(),
quiz: $("#quiz-title").data("name") || "", quiz: $("#quiz-title").data("name") || "",
}, },
callback: (data) => { callback: (data) => {
window.location.href = "/quizzes"; window.location.href = "/quizzes";
}, },
}); });
}; };
const get_questions = () => { const get_questions = () => {
let questions = []; let questions = [];
$(".quiz-card").each((i, el) => { $(".quiz-card").each((i, el) => {
if (!$(el).find(".question").text()) return; if (!$(el).find(".question").text()) return;
let details = {}; let details = {};
let one_correct_option = false; let one_correct_option = false;
details["question"] = $(el).find(".question").text(); details["question"] = $(el).find(".question").text();
details["question_name"] = details["question_name"] =
$(el).find(".question").data("question") || ""; $(el).find(".question").data("question") || "";
Array.from({ length: 4 }, (x, i) => { Array.from({ length: 4 }, (x, i) => {
let num = i + 1; let num = i + 1;
details[`option_${num}`] = $(el) details[`option_${num}`] = $(el)
.find(`.option-${num} .option-input:first`) .find(`.option-${num} .option-input:first`)
.text(); .text();
details[`explanation_${num}`] = $(el) details[`explanation_${num}`] = $(el)
.find(`.option-${num} .option-input:last`) .find(`.option-${num} .option-input:last`)
.text(); .text();
let is_correct = $(el) let is_correct = $(el)
.find(`.option-${num} .option-checkbox`) .find(`.option-${num} .option-checkbox`)
.find("input") .find("input")
.prop("checked"); .prop("checked");
if (is_correct) one_correct_option = true; if (is_correct) one_correct_option = true;
details[`is_correct_${num}`] = is_correct; details[`is_correct_${num}`] = is_correct;
}); });
if (!details["option_1"] || !details["option_2"]) 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) if (!one_correct_option)
frappe.throw( frappe.throw(
__("Each question must have at least one correct option.") __("Each question must have at least one correct option.")
); );
questions.push(details); questions.push(details);
}); });
return questions; return questions;
}; };
const scroll_to_question_container = () => { const scroll_to_question_container = () => {
$([document.documentElement, document.body]).animate( $([document.documentElement, document.body]).animate(
{ {
scrollTop: $(".new-quiz-card").offset().top, scrollTop: $(".new-quiz-card").offset().top,
}, },
1000 1000
); );
$(".new-quiz-card").find(".question").focus(); $(".new-quiz-card").find(".question").focus();
}; };

View File

@@ -1,56 +1,56 @@
frappe.ready(() => { frappe.ready(() => {
$("#load-more").click((e) => { $("#load-more").click((e) => {
search(e); search(e);
}); });
$(".close-search-empty-state").click((e) => { $(".close-search-empty-state").click((e) => {
close_search_empty_state(e); close_search_empty_state(e);
}); });
$("#search-user").keyup(function () { $("#search-user").keyup(function () {
let timer; let timer;
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout(() => { timer = setTimeout(() => {
search.apply(this, arguments); search.apply(this, arguments);
}, 300); }, 300);
}); });
}); });
const search = (e) => { const search = (e) => {
$("#search-empty-state").addClass("hide"); $("#search-empty-state").addClass("hide");
let start = $(e.currentTarget).data("start"); let start = $(e.currentTarget).data("start");
let input = $("#search-user").val(); let input = $("#search-user").val();
if ($(e.currentTarget).prop("nodeName") == "INPUT") start = 0; if ($(e.currentTarget).prop("nodeName") == "INPUT") start = 0;
frappe.call({ frappe.call({
method: "lms.overrides.user.search_users", method: "lms.overrides.user.search_users",
args: { args: {
start: start, start: start,
text: input, text: input,
}, },
callback: (data) => { callback: (data) => {
if ($(e.currentTarget).prop("nodeName") == "INPUT") if ($(e.currentTarget).prop("nodeName") == "INPUT")
$(".member-parent").empty(); $(".member-parent").empty();
if (data.message.user_details.length) if (data.message.user_details.length)
$("#load-more").removeClass("hide"); $("#load-more").removeClass("hide");
else $("#search-empty-state").removeClass("hide"); else $("#search-empty-state").removeClass("hide");
$(".member-parent").append(data.message.user_details); $(".member-parent").append(data.message.user_details);
update_load_more_state(data); update_load_more_state(data);
}, },
}); });
}; };
const close_search_empty_state = (e) => { const close_search_empty_state = (e) => {
$("#search-empty-state").addClass("hide"); $("#search-empty-state").addClass("hide");
$("#search-user").val("").keyup(); $("#search-user").val("").keyup();
}; };
const update_load_more_state = (data) => { const update_load_more_state = (data) => {
$("#load-more").data("start", data.message.start); $("#load-more").data("start", data.message.start);
$("#load-more").data("count", data.message.count); $("#load-more").data("count", data.message.count);
if ($(".member-card").length == $("#load-more").data("count")) { if ($(".member-card").length == $("#load-more").data("count")) {
$("#load-more").addClass("hide"); $("#load-more").addClass("hide");
} }
}; };

View File

@@ -1,56 +1,56 @@
frappe.ready(() => { frappe.ready(() => {
$("#export-as-pdf").click((e) => { $("#export-as-pdf").click((e) => {
export_as_png(e); export_as_png(e);
}); });
}); });
const export_as_pdf = (e) => { const export_as_pdf = (e) => {
var formData = new FormData(); var formData = new FormData();
//Push the HTML content into an element //Push the HTML content into an element
formData.append("html", $("#certificate-card").html()); formData.append("html", $("#certificate-card").html());
var blob = new Blob([], { type: "text/xml" }); var blob = new Blob([], { type: "text/xml" });
formData.append("blob", blob); formData.append("blob", blob);
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open( xhr.open(
"POST", "POST",
"/api/method/lms.lms.doctype.lms_certificate.lms_certificate.get_certificate_pdf" "/api/method/lms.lms.doctype.lms_certificate.lms_certificate.get_certificate_pdf"
); );
xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token); xhr.setRequestHeader("X-Frappe-CSRF-Token", frappe.csrf_token);
xhr.responseType = "arraybuffer"; xhr.responseType = "arraybuffer";
xhr.onload = function (success) { xhr.onload = function (success) {
if (this.status === 200) { if (this.status === 200) {
var blob = new Blob([success.currentTarget.response], { var blob = new Blob([success.currentTarget.response], {
type: "application/pdf", type: "application/pdf",
}); });
var objectUrl = URL.createObjectURL(blob); var objectUrl = URL.createObjectURL(blob);
//Open report in a new window //Open report in a new window
window.open(objectUrl); window.open(objectUrl);
} }
}; };
xhr.send(formData); xhr.send(formData);
}; };
const export_as_png = (e) => { const export_as_png = (e) => {
let button = $(e.currentTarget); let button = $(e.currentTarget);
button.text(__("Exporting...")); button.text(__("Exporting..."));
html2canvas(document.querySelector("#certificate-card"), { html2canvas(document.querySelector("#certificate-card"), {
scrollY: -window.scrollY, scrollY: -window.scrollY,
scrollX: 0, scrollX: 0,
}) })
.then(function (canvas) { .then(function (canvas) {
let dataURL = canvas.toDataURL("image/png"); let dataURL = canvas.toDataURL("image/png");
let a = document.createElement("a"); let a = document.createElement("a");
a.href = dataURL; a.href = dataURL;
a.download = button.attr("data-certificate-name"); a.download = button.attr("data-certificate-name");
a.click(); a.click();
}) })
.finally(() => { .finally(() => {
button.text(__("Export")); button.text(__("Export"));
}); });
}; };

View File

@@ -1,414 +1,414 @@
frappe.ready(() => { frappe.ready(() => {
hide_wrapped_mentor_cards(); hide_wrapped_mentor_cards();
$("#cancel-request").click((e) => { $("#cancel-request").click((e) => {
cancel_mentor_request(e); cancel_mentor_request(e);
}); });
$(".view-all-mentors").click((e) => { $(".view-all-mentors").click((e) => {
view_all_mentors(e); view_all_mentors(e);
}); });
$(".review-link").click((e) => { $(".review-link").click((e) => {
show_review_dialog(e); show_review_dialog(e);
}); });
$(".icon-rating").click((e) => { $(".icon-rating").click((e) => {
highlight_rating(e); highlight_rating(e);
}); });
$("#submit-review").click((e) => { $("#submit-review").click((e) => {
submit_review(e); submit_review(e);
}); });
$("#certification").click((e) => { $("#certification").click((e) => {
create_certificate(e); create_certificate(e);
}); });
$("#submit-for-review").click((e) => { $("#submit-for-review").click((e) => {
submit_for_review(e); submit_for_review(e);
}); });
$("#apply-certificate").click((e) => { $("#apply-certificate").click((e) => {
apply_cetificate(e); apply_cetificate(e);
}); });
$("#slot-date").on("change", (e) => { $("#slot-date").on("change", (e) => {
display_slots(e); display_slots(e);
}); });
$("#submit-slot").click((e) => { $("#submit-slot").click((e) => {
submit_slot(e); submit_slot(e);
}); });
$(".close-slot-modal").click((e) => { $(".close-slot-modal").click((e) => {
close_slot_modal(e); close_slot_modal(e);
}); });
$(document).on("click", ".slot", (e) => { $(document).on("click", ".slot", (e) => {
select_slot(e); select_slot(e);
}); });
$(".btn-attach").click((e) => { $(".btn-attach").click((e) => {
show_upload_modal(e); show_upload_modal(e);
}); });
$(".btn-clear").click((e) => { $(".btn-clear").click((e) => {
clear_image(e); clear_image(e);
}); });
$(".btn-tag").click((e) => { $(".btn-tag").click((e) => {
add_tag(e); add_tag(e);
}); });
$(".btn-save-course").click((e) => { $(".btn-save-course").click((e) => {
save_course(e); save_course(e);
}); });
$(".btn-delete-tag").click((e) => { $(".btn-delete-tag").click((e) => {
remove_tag(e); remove_tag(e);
}); });
if ($("#description").length) { if ($("#description").length) {
make_editor(); make_editor();
} }
}); });
const hide_wrapped_mentor_cards = () => { const hide_wrapped_mentor_cards = () => {
let offset_top_prev; let offset_top_prev;
$(".member-parent .member-card").each(function () { $(".member-parent .member-card").each(function () {
var offset_top = $(this).offset().top; var offset_top = $(this).offset().top;
if (offset_top > offset_top_prev) { if (offset_top > offset_top_prev) {
$(this).addClass("wrapped").slideUp("fast"); $(this).addClass("wrapped").slideUp("fast");
} }
if (!offset_top_prev) { if (!offset_top_prev) {
offset_top_prev = offset_top; offset_top_prev = offset_top;
} }
}); });
if ($(".wrapped").length < 1) { if ($(".wrapped").length < 1) {
$(".view-all-mentors").hide(); $(".view-all-mentors").hide();
} }
}; };
const cancel_mentor_request = (e) => { const cancel_mentor_request = (e) => {
e.preventDefault(); e.preventDefault();
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_mentor_request.lms_mentor_request.cancel_request", method: "lms.lms.doctype.lms_mentor_request.lms_mentor_request.cancel_request",
args: { args: {
course: decodeURIComponent($(e.currentTarget).attr("data-course")), course: decodeURIComponent($(e.currentTarget).attr("data-course")),
}, },
callback: (data) => { callback: (data) => {
if (data.message == "OK") { if (data.message == "OK") {
$("#mentor-request").removeClass("hide"); $("#mentor-request").removeClass("hide");
$("#already-applied").addClass("hide"); $("#already-applied").addClass("hide");
} }
}, },
}); });
}; };
const view_all_mentors = (e) => { const view_all_mentors = (e) => {
$(".wrapped").each((i, element) => { $(".wrapped").each((i, element) => {
$(element).slideToggle("slow"); $(element).slideToggle("slow");
}); });
var text_element = $( var text_element = $(
".view-all-mentors .course-instructor .all-mentors-text" ".view-all-mentors .course-instructor .all-mentors-text"
); );
var text = var text =
text_element.text() == "View all mentors" text_element.text() == "View all mentors"
? "View less" ? "View less"
: "View all mentors"; : "View all mentors";
text_element.text(text); text_element.text(text);
if ($(".mentor-icon").css("transform") == "none") { if ($(".mentor-icon").css("transform") == "none") {
$(".mentor-icon").css("transform", "rotate(180deg)"); $(".mentor-icon").css("transform", "rotate(180deg)");
} else { } else {
$(".mentor-icon").css("transform", ""); $(".mentor-icon").css("transform", "");
} }
}; };
const show_review_dialog = (e) => { const show_review_dialog = (e) => {
e.preventDefault(); e.preventDefault();
$("#review-modal").modal("show"); $("#review-modal").modal("show");
}; };
const highlight_rating = (e) => { const highlight_rating = (e) => {
var rating = $(e.currentTarget).attr("data-rating"); var rating = $(e.currentTarget).attr("data-rating");
$(".icon-rating").removeClass("star-click"); $(".icon-rating").removeClass("star-click");
$(".icon-rating").each((i, elem) => { $(".icon-rating").each((i, elem) => {
if (i <= rating - 1) { if (i <= rating - 1) {
$(elem).addClass("star-click"); $(elem).addClass("star-click");
} }
}); });
}; };
const submit_review = (e) => { const submit_review = (e) => {
e.preventDefault(); e.preventDefault();
let rating = $(".rating-field").children(".star-click").length; let rating = $(".rating-field").children(".star-click").length;
let review = $(".review-field").val(); let review = $(".review-field").val();
if (!rating) { if (!rating) {
$(".error-field").text("Please provide a rating."); $(".error-field").text("Please provide a rating.");
return; return;
} }
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course_review.lms_course_review.submit_review", method: "lms.lms.doctype.lms_course_review.lms_course_review.submit_review",
args: { args: {
rating: rating, rating: rating,
review: review, review: review,
course: decodeURIComponent($(e.currentTarget).attr("data-course")), course: decodeURIComponent($(e.currentTarget).attr("data-course")),
}, },
callback: (data) => { callback: (data) => {
if (data.message == "OK") { if (data.message == "OK") {
$(".review-modal").modal("hide"); $(".review-modal").modal("hide");
frappe.show_alert( frappe.show_alert(
{ {
message: __("Review submitted."), message: __("Review submitted."),
indicator: "green", indicator: "green",
}, },
3 3
); );
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 1000); }, 1000);
} }
}, },
}); });
}; };
const create_certificate = (e) => { const create_certificate = (e) => {
e.preventDefault(); e.preventDefault();
course = $(e.currentTarget).attr("data-course"); course = $(e.currentTarget).attr("data-course");
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate", method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
args: { args: {
course: course, course: course,
}, },
callback: (data) => { callback: (data) => {
window.location.href = `/courses/${course}/${data.message.name}`; window.location.href = `/courses/${course}/${data.message.name}`;
}, },
}); });
}; };
const element_not_in_viewport = (el) => { const element_not_in_viewport = (el) => {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
return ( return (
rect.bottom < 0 || rect.bottom < 0 ||
rect.right < 0 || rect.right < 0 ||
rect.left > window.innerWidth || rect.left > window.innerWidth ||
rect.top > window.innerHeight rect.top > window.innerHeight
); );
}; };
const submit_for_review = (e) => { const submit_for_review = (e) => {
let course = $(e.currentTarget).data("course"); let course = $(e.currentTarget).data("course");
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.submit_for_review", method: "lms.lms.doctype.lms_course.lms_course.submit_for_review",
args: { args: {
course: course, course: course,
}, },
callback: (data) => { callback: (data) => {
if (data.message == "No Chp") { if (data.message == "No Chp") {
frappe.msgprint( frappe.msgprint(
__(`There are no chapters in this course. __(`There are no chapters in this course.
Please add chapters and lessons to your course before you submit it for review.`) Please add chapters and lessons to your course before you submit it for review.`)
); );
} else if (data.message == "OK") { } else if (data.message == "OK") {
frappe.show_alert( frappe.show_alert(
{ {
message: __( message: __(
"Your course has been submitted for review." "Your course has been submitted for review."
), ),
indicator: "green", indicator: "green",
}, },
3 3
); );
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 1000); }, 1000);
} }
}, },
}); });
}; };
const apply_cetificate = (e) => { const apply_cetificate = (e) => {
$("#slot-modal").modal("show"); $("#slot-modal").modal("show");
}; };
const submit_slot = (e) => { const submit_slot = (e) => {
e.preventDefault(); e.preventDefault();
const slot = window.selected_slot; const slot = window.selected_slot;
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_certificate_request", method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_certificate_request",
args: { args: {
course: slot.data("course"), course: slot.data("course"),
date: $("#slot-date").val(), date: $("#slot-date").val(),
day: slot.data("day"), day: slot.data("day"),
start_time: slot.data("start"), start_time: slot.data("start"),
end_time: slot.data("end"), end_time: slot.data("end"),
}, },
callback: (data) => { callback: (data) => {
$("#slot-modal").modal("hide"); $("#slot-modal").modal("hide");
frappe.show_alert( frappe.show_alert(
{ {
message: __( message: __(
"Your slot has been booked. Prepare well for the evaluations." "Your slot has been booked. Prepare well for the evaluations."
), ),
indicator: "green", indicator: "green",
}, },
3 3
); );
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 3000); }, 3000);
}, },
}); });
}; };
const display_slots = (e) => { const display_slots = (e) => {
frappe.call({ frappe.call({
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule", method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
args: { args: {
course: $(e.currentTarget).data("course"), course: $(e.currentTarget).data("course"),
date: $(e.currentTarget).val(), date: $(e.currentTarget).val(),
}, },
callback: (data) => { callback: (data) => {
let options = ""; let options = "";
data.message.forEach((obj) => { data.message.forEach((obj) => {
options += `<button type="button" class="btn btn-sm btn-secondary mb-3 mr-3 slot hide" options += `<button type="button" class="btn btn-sm btn-secondary mb-3 mr-3 slot hide"
data-course="${$(e.currentTarget).data("course")}" data-course="${$(e.currentTarget).data("course")}"
data-day="${obj.day}" data-start="${ data-day="${obj.day}" data-start="${
obj.start_time obj.start_time
}" data-end="${obj.end_time}"> }" data-end="${obj.end_time}">
${format_time(obj.start_time)} - ${format_time( ${format_time(obj.start_time)} - ${format_time(
obj.end_time obj.end_time
)}</button>`; )}</button>`;
}); });
e.preventDefault(); e.preventDefault();
$("#slot-modal .slots").html(options); $("#slot-modal .slots").html(options);
const weekday = [ const weekday = [
"Sunday", "Sunday",
"Monday", "Monday",
"Tuesday", "Tuesday",
"Wednesday", "Wednesday",
"Thursday", "Thursday",
"Friday", "Friday",
"Saturday", "Saturday",
]; ];
const day = weekday[new Date($(e.currentTarget).val()).getDay()]; const day = weekday[new Date($(e.currentTarget).val()).getDay()];
$(".slot").addClass("hide"); $(".slot").addClass("hide");
$(".slot-label").addClass("hide"); $(".slot-label").addClass("hide");
if ($(`[data-day='${day}']`).length) { if ($(`[data-day='${day}']`).length) {
$(".slot-label").removeClass("hide"); $(".slot-label").removeClass("hide");
$(`[data-day='${day}']`).removeClass("hide"); $(`[data-day='${day}']`).removeClass("hide");
$("#no-slots-message").addClass("hide"); $("#no-slots-message").addClass("hide");
} else { } else {
$("#no-slots-message").removeClass("hide"); $("#no-slots-message").removeClass("hide");
} }
}, },
}); });
}; };
const select_slot = (e) => { const select_slot = (e) => {
$(".slot").removeClass("btn-outline-primary"); $(".slot").removeClass("btn-outline-primary");
$(e.currentTarget).addClass("btn-outline-primary"); $(e.currentTarget).addClass("btn-outline-primary");
window.selected_slot = $(e.currentTarget); window.selected_slot = $(e.currentTarget);
}; };
const format_time = (time) => { const format_time = (time) => {
let date = moment(new Date()).format("ddd MMM DD YYYY"); let date = moment(new Date()).format("ddd MMM DD YYYY");
return moment(`${date} ${time}`).format("HH:mm a"); return moment(`${date} ${time}`).format("HH:mm a");
}; };
const close_slot_modal = (e) => { const close_slot_modal = (e) => {
$("#slot-date").val(""); $("#slot-date").val("");
$(".slot-label").addClass("hide"); $(".slot-label").addClass("hide");
}; };
const show_upload_modal = () => { const show_upload_modal = () => {
new frappe.ui.FileUploader({ new frappe.ui.FileUploader({
folder: "Home/Attachments", folder: "Home/Attachments",
restrictions: { restrictions: {
allowed_file_types: ["image/*"], allowed_file_types: ["image/*"],
}, },
on_success: (file_doc) => { on_success: (file_doc) => {
$(".course-image-attachment").removeClass("hide"); $(".course-image-attachment").removeClass("hide");
$(".course-image-attachment a") $(".course-image-attachment a")
.attr("href", file_doc.file_url) .attr("href", file_doc.file_url)
.text(file_doc.file_url); .text(file_doc.file_url);
$(".btn-attach").addClass("hide"); $(".btn-attach").addClass("hide");
}, },
}); });
}; };
const clear_image = () => { const clear_image = () => {
$(".course-image-attachment").addClass("hide"); $(".course-image-attachment").addClass("hide");
$(".course-image-attachment a").removeAttr("href"); $(".course-image-attachment a").removeAttr("href");
$(".btn-attach").removeClass("hide"); $(".btn-attach").removeClass("hide");
}; };
const add_tag = (e) => { const add_tag = (e) => {
$(`<div class="course-card-pills" contenteditable="true" $(`<div class="course-card-pills" contenteditable="true"
data-placeholder="${__("Tag")}"></div>`).insertBefore(`.btn-tag`); data-placeholder="${__("Tag")}"></div>`).insertBefore(`.btn-tag`);
}; };
const save_course = (e) => { const save_course = (e) => {
let tags = $(".course-card-pills") let tags = $(".course-card-pills")
.map((i, el) => $(el).text().trim()) .map((i, el) => $(el).text().trim())
.get(); .get();
tags = tags.filter((word) => word.trim().length > 0); tags = tags.filter((word) => word.trim().length > 0);
frappe.call({ frappe.call({
method: "lms.lms.doctype.lms_course.lms_course.save_course", method: "lms.lms.doctype.lms_course.lms_course.save_course",
args: { args: {
tags: tags.join(", "), tags: tags.join(", "),
title: $("#title").text(), title: $("#title").text(),
short_introduction: $("#intro").text(), short_introduction: $("#intro").text(),
video_link: $("#video-link").text(), video_link: $("#video-link").text(),
image: $("#image").attr("href"), image: $("#image").attr("href"),
description: this.code_field_group.fields_dict["code_md"].value, description: this.code_field_group.fields_dict["code_md"].value,
course: $("#title").data("course") course: $("#title").data("course")
? $("#title").data("course") ? $("#title").data("course")
: "", : "",
published: $("#published").prop("checked") ? 1 : 0, published: $("#published").prop("checked") ? 1 : 0,
upcoming: $("#upcoming").prop("checked") ? 1 : 0, upcoming: $("#upcoming").prop("checked") ? 1 : 0,
}, },
callback: (data) => { callback: (data) => {
frappe.show_alert({ frappe.show_alert({
message: __("Saved"), message: __("Saved"),
indicator: "green", indicator: "green",
}); });
setTimeout(() => { setTimeout(() => {
window.location.href = `/courses/${data.message}?edit=1`; window.location.href = `/courses/${data.message}?edit=1`;
}, 1000); }, 1000);
}, },
}); });
}; };
const remove_tag = (e) => { const remove_tag = (e) => {
$(e.currentTarget).closest(".course-card-pills").remove(); $(e.currentTarget).closest(".course-card-pills").remove();
}; };
const make_editor = () => { const make_editor = () => {
this.code_field_group = new frappe.ui.FieldGroup({ this.code_field_group = new frappe.ui.FieldGroup({
fields: [ fields: [
{ {
fieldname: "code_md", fieldname: "code_md",
fieldtype: "Code", fieldtype: "Code",
options: "Markdown", options: "Markdown",
wrap: true, wrap: true,
max_lines: Infinity, max_lines: Infinity,
min_lines: 20, min_lines: 20,
default: $("#description").data("description"), default: $("#description").data("description"),
depends_on: 'eval:doc.type=="Markdown"', depends_on: 'eval:doc.type=="Markdown"',
}, },
], ],
body: $("#description").get(0), body: $("#description").get(0),
}); });
this.code_field_group.make(); this.code_field_group.make();
$("#description .form-section:last").removeClass("empty-section"); $("#description .form-section:last").removeClass("empty-section");
$("#description .frappe-control").removeClass("hide-control"); $("#description .frappe-control").removeClass("hide-control");
$("#description .form-column").addClass("p-0"); $("#description .form-column").addClass("p-0");
}; };

View File

@@ -1,58 +1,58 @@
frappe.ready(() => { frappe.ready(() => {
generate_graph("New Signups"); generate_graph("New Signups");
generate_graph("Course Enrollments"); generate_graph("Course Enrollments");
$(".nav-link").click((e) => { $(".nav-link").click((e) => {
change_hash(e); change_hash(e);
}); });
if (window.location.hash) { if (window.location.hash) {
open_tab(); open_tab();
} }
}); });
const generate_graph = (chart_name) => { const generate_graph = (chart_name) => {
let date = frappe.datetime; let date = frappe.datetime;
frappe.call({ frappe.call({
method: "lms.lms.utils.get_chart_data", method: "lms.lms.utils.get_chart_data",
args: { args: {
chart_name: chart_name, chart_name: chart_name,
timespan: "Select Date Range", timespan: "Select Date Range",
timegrain: "Daily", timegrain: "Daily",
from_date: date.add_days(date.get_today(), -30), from_date: date.add_days(date.get_today(), -30),
to_date: date.add_days(date.get_today(), +1), to_date: date.add_days(date.get_today(), +1),
}, },
callback: (data) => { callback: (data) => {
render_chart(data.message, chart_name); render_chart(data.message, chart_name);
}, },
}); });
}; };
const render_chart = (data, chart_name) => { const render_chart = (data, chart_name) => {
let dom_element = let dom_element =
chart_name == "Course Enrollments" chart_name == "Course Enrollments"
? "#course-enrollments" ? "#course-enrollments"
: "#new-signups"; : "#new-signups";
const chart = new frappe.Chart(dom_element, { const chart = new frappe.Chart(dom_element, {
title: chart_name, title: chart_name,
data: data, data: data,
type: "line", type: "line",
height: 250, height: 250,
colors: ["#4563f1"], colors: ["#4563f1"],
axisOptions: { axisOptions: {
xIsSeries: 1, xIsSeries: 1,
}, },
lineOptions: { lineOptions: {
regionFill: 1, regionFill: 1,
}, },
}); });
}; };
const change_hash = (e) => { const change_hash = (e) => {
window.location.hash = $(e.currentTarget).attr("href"); window.location.hash = $(e.currentTarget).attr("href");
}; };
const open_tab = () => { const open_tab = () => {
$(`a[href="${window.location.hash}"]`).click(); $(`a[href="${window.location.hash}"]`).click();
}; };

View File

@@ -1,42 +1,42 @@
frappe.ready(() => { frappe.ready(() => {
$("#report").click((e) => { $("#report").click((e) => {
open_report_dialog(e); open_report_dialog(e);
}); });
$("#submit-report").click((e) => { $("#submit-report").click((e) => {
report(e); report(e);
}); });
}); });
const open_report_dialog = (e) => { const open_report_dialog = (e) => {
e.preventDefault(); e.preventDefault();
if (frappe.session.user == "Guest") { if (frappe.session.user == "Guest") {
window.location.href = `/login?redirect-to=/jobs/${$( window.location.href = `/login?redirect-to=/jobs/${$(
e.currentTarget e.currentTarget
).data("job")}`; ).data("job")}`;
return; return;
} }
$("#report-modal").modal("show"); $("#report-modal").modal("show");
}; };
const report = (e) => { const report = (e) => {
frappe.call({ frappe.call({
method: "lms.job.doctype.job_opportunity.job_opportunity.report", method: "lms.job.doctype.job_opportunity.job_opportunity.report",
args: { args: {
job: $(e.currentTarget).data("job"), job: $(e.currentTarget).data("job"),
reason: $(".report-field").val(), reason: $(".report-field").val(),
}, },
callback: (data) => { callback: (data) => {
$(".report-modal").modal("hide"); $(".report-modal").modal("hide");
frappe.show_alert( frappe.show_alert(
{ {
message: __( message: __(
"Thanks for informing us about this post. The admin will look into it and take an appropriate action soon." "Thanks for informing us about this post. The admin will look into it and take an appropriate action soon."
), ),
indicator: "green", indicator: "green",
}, },
5 5
); );
}, },
}); });
}; };

View File

@@ -1,56 +1,56 @@
frappe.ready(() => { frappe.ready(() => {
make_profile_active_in_navbar(); make_profile_active_in_navbar();
$(".role").change((e) => { $(".role").change((e) => {
save_role(e); save_role(e);
}); });
$(".nav-link").click((e) => { $(".nav-link").click((e) => {
change_hash(e); change_hash(e);
}); });
if (window.location.hash) { if (window.location.hash) {
open_tab(); open_tab();
} }
}); });
const make_profile_active_in_navbar = () => { const make_profile_active_in_navbar = () => {
let member_name = $(".profile-name").data("name"); let member_name = $(".profile-name").data("name");
if (member_name == frappe.session.user) { if (member_name == frappe.session.user) {
setTimeout(() => { setTimeout(() => {
let link_array = $(".nav-link").filter( let link_array = $(".nav-link").filter(
(i, elem) => $(elem).text().trim() === "My Profile" (i, elem) => $(elem).text().trim() === "My Profile"
); );
link_array.length && $(link_array[0]).addClass("active"); link_array.length && $(link_array[0]).addClass("active");
}, 0); }, 0);
} }
}; };
const save_role = (e) => { const save_role = (e) => {
let member_name = $(".profile-name").data("name"); let member_name = $(".profile-name").data("name");
let role = $(e.currentTarget).children("input"); let role = $(e.currentTarget).children("input");
frappe.call({ frappe.call({
method: "lms.overrides.user.save_role", method: "lms.overrides.user.save_role",
args: { args: {
user: member_name, user: member_name,
role: role.data("role"), role: role.data("role"),
value: role.prop("checked") ? 1 : 0, value: role.prop("checked") ? 1 : 0,
}, },
callback: (data) => { callback: (data) => {
if (data.message) { if (data.message) {
frappe.show_alert({ frappe.show_alert({
message: __("Saved"), message: __("Saved"),
indicator: "green", indicator: "green",
}); });
} }
}, },
}); });
}; };
const change_hash = (e) => { const change_hash = (e) => {
window.location.hash = $(e.currentTarget).attr("href"); window.location.hash = $(e.currentTarget).attr("href");
}; };
const open_tab = () => { const open_tab = () => {
$(`a[href="${window.location.hash}"]`).click(); $(`a[href="${window.location.hash}"]`).click();
}; };

View File

@@ -17,7 +17,7 @@ def get_context(context):
try: try:
context.member = frappe.get_doc("User", {"username": username}) context.member = frappe.get_doc("User", {"username": username})
except: except Exception:
context.template = "www/404.html" context.template = "www/404.html"
return return