diff --git a/lms/public/css/style.css b/lms/public/css/style.css index fded8915..1b704a49 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -121,8 +121,7 @@ textarea.field-input { } .outline-lesson { - border-bottom: 1px solid var(--gray-300); - padding: 1rem 0; + padding: 0.5rem 0; } .common-card-style .outline-lesson:last-of-type { @@ -160,6 +159,12 @@ textarea.field-input { padding-top: 0.5rem; } +.lesson-parent .breadcrumb { + border-bottom: 1px solid var(--gray-300); + margin-bottom: 2rem; + padding-bottom: 1rem; +} + body { background-color: #FFFFFF; } @@ -764,15 +769,12 @@ input[type=checkbox] { } .course-content-parent .course-home-headings { - margin: 0 0 1rem; + margin: 0 0 0.5rem; width: 100%; } .lesson-pagination { - display: flex; - justify-content: space-between; - align-items: center; - margin-top: 2rem + margin: 2rem 0; } .lesson-video { @@ -937,7 +939,7 @@ input[type=checkbox] { } .progress-bar { - background-color: var(--accent-color); + background-color: var(--primary-color); } .progress-percent { diff --git a/lms/www/batch/edit.html b/lms/www/batch/edit.html index a99e8d75..8c3a0948 100644 --- a/lms/www/batch/edit.html +++ b/lms/www/batch/edit.html @@ -46,7 +46,7 @@
- +
@@ -60,6 +60,9 @@
+ {% if lesson.body %} +
{{ lesson.body }}
+ {% endif %} @@ -86,5 +89,7 @@ {% endif %} {{ include_script('controls.bundle.js') }} + + {% endblock %} diff --git a/lms/www/batch/edit.js b/lms/www/batch/edit.js index c162f7bb..2a06bc59 100644 --- a/lms/www/batch/edit.js +++ b/lms/www/batch/edit.js @@ -1,5 +1,9 @@ frappe.ready(() => { let self = this; + if ($("#current-lesson-content").length) { + parse_string_to_lesson(); + } + setup_editor(); fetch_quiz_list(); @@ -8,19 +12,102 @@ frappe.ready(() => { }); }); +const parse_string_to_lesson = () => { + let lesson_content = $("#current-lesson-content").html(); + let lesson_blocks = []; + + lesson_content.split("\n").forEach((block) => { + if (block.includes("{{ YouTubeVideo")) { + let youtube_id = block.match(/'([^']+)'/)[1]; + lesson_blocks.push({ + type: "youtube", + data: { + youtube: youtube_id, + }, + }); + } else if (block.includes("{{ Quiz")) { + let quiz = block.match(/'([^']+)'/)[1]; + lesson_blocks.push({ + type: "quiz", + data: { + quiz: quiz, + }, + }); + } else { + lesson_blocks.push({ + type: "paragraph", + data: { + text: block, + }, + }); + } + }); + + this.blocks = lesson_blocks; +}; + const setup_editor = () => { self.editor = new EditorJS({ holder: "lesson-content", tools: { youtube: YouTubeVideo, quiz: Quiz, + paragraph: { + class: Paragraph, + inlineToolbar: true, + config: { + preserveBlank: true, + }, + }, + }, + data: { + blocks: self.blocks ? self.blocks : [], }, }); }; const save_lesson = (e) => { self.editor.save().then((outputData) => { - parse_lesson(outputData); + parse_lesson_to_string(outputData); + }); +}; + +const parse_lesson_to_string = (data) => { + let lesson_content = ""; + data.blocks.forEach((block) => { + if (block.type == "youtube") { + lesson_content += `{{ YouTubeVideo("${block.data.youtube}") }}\n`; + } else if (block.type == "quiz") { + lesson_content += `{{ Quiz("${block.data.quiz}") }}\n`; + } else if (block.type == "paragraph") { + lesson_content += `${block.data.text}\n`; + } + }); + save(lesson_content); +}; + +const save = (lesson_content) => { + let lesson = $("#lesson-title").data("lesson"); + + frappe.call({ + method: "lms.lms.doctype.lms_course.lms_course.save_lesson", + args: { + title: $("#lesson-title").val(), + body: lesson_content, + chapter: $("#lesson-title").data("chapter"), + preview: 0, + idx: $("#lesson-title").data("index"), + lesson: lesson ? lesson : "", + }, + callback: (data) => { + frappe.show_alert({ + message: __("Saved"), + indicator: "green", + }); + setTimeout(() => { + window.location.href = window.location.href.split("?")[0]; + }, 1000); + }, }); }; @@ -33,9 +120,11 @@ const fetch_quiz_list = () => { }); }; -const parse_lesson = (data) => {}; - class YouTubeVideo { + constructor({ data }) { + this.data = data; + } + static get toolbox() { return { title: "YouTube Video", @@ -43,8 +132,17 @@ class YouTubeVideo { } render() { - let self = this; this.wrapper = document.createElement("div"); + if (this.data && this.data.youtube) { + $(this.wrapper).html(this.render_youtube(this.data.youtube)); + } else { + this.render_youtube_dialog(); + } + return this.wrapper; + } + + render_youtube_dialog() { + let self = this; let youtubedialog = new frappe.ui.Dialog({ title: __("YouTube Video"), fields: [ @@ -59,23 +157,26 @@ class YouTubeVideo { primary_action(values) { youtubedialog.hide(); self.youtube = values.youtube; - $(self.wrapper).html(` `); + $(self.wrapper).html(self.render_youtube(values.youtube)); }, }); youtubedialog.show(); - return this.wrapper; + } + + render_youtube(youtube) { + return ``; } save(block_content) { return { - youtube: this.youtube, + youtube: this.data.youtube || this.youtube, }; } } @@ -87,8 +188,21 @@ class Quiz { }; } + constructor({ data }) { + this.data = data; + } + render() { this.wrapper = document.createElement("div"); + if (this.data && this.data.quiz) { + $(this.wrapper).html(this.render_quiz(this.data.quiz)); + } else { + this.render_quiz_dialog(); + } + return this.wrapper; + } + + render_quiz_dialog() { let self = this; let quizdialog = new frappe.ui.Dialog({ title: __("Select a Quiz"), @@ -105,11 +219,7 @@ class Quiz { primary_action(values) { self.quiz = values.quiz; quizdialog.hide(); - $(self.wrapper).html( - `
- Quiz: ${self.quiz} -
` - ); + $(self.wrapper).html(self.render_quiz(self.quiz)); }, }); quizdialog.show(); @@ -117,12 +227,17 @@ class Quiz { $(".modal-body").css("min-height", "300px"); $(".modal-body input").focus(); }, 1000); - return this.wrapper; + } + + render_quiz(quiz) { + return `
+ Quiz: ${quiz} +
`; } save(block_content) { return { - quiz: this.quiz, + quiz: this.data.quiz || this.quiz, }; } } @@ -136,7 +251,6 @@ class Video { render() { this.wrapper = document.createElement("div"); - let self = this; new frappe.ui.FileUploader({ disable_file_browser: true, folder: "Home/Attachments", diff --git a/lms/www/batch/edit.py b/lms/www/batch/edit.py index 1734b8e4..6934e069 100644 --- a/lms/www/batch/edit.py +++ b/lms/www/batch/edit.py @@ -9,6 +9,10 @@ def get_context(context): chapter_index = frappe.form_dict.get("chapter") lesson_index = frappe.form_dict.get("lesson") lesson_number = f"{chapter_index}.{lesson_index}" + context.lesson_index = lesson_index + context.chapter = frappe.db.get_value( + "Chapter Reference", {"idx": chapter_index, "parent": context.course.name}, "chapter" + ) context.lesson = get_current_lesson_details(lesson_number, context, True) context.is_moderator = has_course_moderator_role() instructor = is_instructor(context.course.name) diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index 21d2911e..0f270bb2 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -42,7 +42,7 @@ {{ widgets.CourseOutline(course=course, membership=membership, lesson_page=True) }} -
+
{{ BreadCrumb(course, lesson) }} {{ LessonContent(lesson) }} {% if course.status == "Approved" and not course.upcoming %} @@ -85,7 +85,7 @@ {% endif %}
-
{% if prev_url %} -
- -
+ {% endif %} {% if next_url %} -
- -
+ {% endif %}
{% endif %} diff --git a/lms/www/courses/create.js b/lms/www/courses/create.js index c6706370..74e5fead 100644 --- a/lms/www/courses/create.js +++ b/lms/www/courses/create.js @@ -75,7 +75,7 @@ const save_course = (e) => { indicator: "green", }); setTimeout(() => { - window.location.href = `/courses/${data.message}`; + window.location.href = `/courses/${data.message}/outline`; }, 1000); }, }); diff --git a/lms/www/courses/outline.html b/lms/www/courses/outline.html index eee6fe9e..b0341d8a 100644 --- a/lms/www/courses/outline.html +++ b/lms/www/courses/outline.html @@ -52,9 +52,12 @@ {{ chapter.title }}
+ + {% if chapter.description %}
{{ chapter.description }}
+ {% endif %} {% for lesson in lessons %}