From 211c69bb41169690fa0065d40fc4a673076da234 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 5 May 2023 11:53:04 +0530 Subject: [PATCH] feat: Video and Header component for a lesson --- lms/public/css/style.css | 35 +++++++-- lms/www/batch/edit.html | 22 +++++- lms/www/batch/edit.js | 136 +++++++++++++++++++++++++++-------- lms/www/batch/edit.py | 1 + lms/www/batch/learn.html | 4 +- lms/www/batch/learn.js | 4 -- lms/www/batch/learn.py | 1 + lms/www/courses/create.html | 10 ++- lms/www/courses/create.js | 2 - lms/www/courses/index.html | 2 +- lms/www/courses/outline.html | 16 ++--- lms/www/courses/outline.js | 4 +- 12 files changed, 178 insertions(+), 59 deletions(-) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 1b704a49..a7d31474 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -3,11 +3,7 @@ --text-3-8xl: 34px; --text-4xl: 36px; --primary-color: var(--gray-900); - --accent-color: #0B9E92 -} - -.btn.btn-primary { - background-color: var(--primary-color); + --primary: var(--gray-900); } .nav-link .course-list-count { @@ -121,7 +117,7 @@ textarea.field-input { } .outline-lesson { - padding: 0.5rem 0; + padding: 0.75rem 0; } .common-card-style .outline-lesson:last-of-type { @@ -165,6 +161,31 @@ textarea.field-input { padding-bottom: 1rem; } +.form-width { + width: 50%; +} + +@media (max-width: 768px) { + .form-width { + width: 75%; + } +} + +.clickable { + color: var(--gray-900); + font-weight: 500; +} + +.clickable:hover { + color: var(--gray-900); + text-decoration: none; +} + +.form-checkbox { + display: flex; + align-items: center; +} + body { background-color: #FFFFFF; } @@ -1487,7 +1508,7 @@ pre { } .reviews-parent .progress-bar { - background-color: var(--accent-color); + background-color: var(--primary-color); } .course-home-top-container { diff --git a/lms/www/batch/edit.html b/lms/www/batch/edit.html index 8c3a0948..eaf13fb9 100644 --- a/lms/www/batch/edit.html +++ b/lms/www/batch/edit.html @@ -11,7 +11,7 @@ {% block content %}
{{ Header() }} -
+
{{ CreateLesson() }}
@@ -20,13 +20,22 @@ {% macro Header() %}
-
+
+ + {% if lesson.name %} + + + {{ _("Preview") }} + + + {% endif %} +
{{ course.title if course.name else _("Course Outline") }}
@@ -46,10 +55,17 @@
- +
+
+ +
+
diff --git a/lms/www/batch/edit.js b/lms/www/batch/edit.js index 2a06bc59..6da08df9 100644 --- a/lms/www/batch/edit.js +++ b/lms/www/batch/edit.js @@ -12,6 +12,35 @@ frappe.ready(() => { }); }); +const setup_editor = () => { + self.editor = new EditorJS({ + holder: "lesson-content", + tools: { + header: { + class: Header, + inlineToolbar: ["bold", "italic", "link"], + config: { + levels: [4, 5, 6], + defaultLevel: 5, + }, + }, + paragraph: { + class: Paragraph, + inlineToolbar: true, + config: { + preserveBlank: true, + }, + }, + youtube: YouTubeVideo, + quiz: Quiz, + upload: Upload, + }, + data: { + blocks: self.blocks ? self.blocks : [], + }, + }); +}; + const parse_string_to_lesson = () => { let lesson_content = $("#current-lesson-content").html(); let lesson_blocks = []; @@ -33,6 +62,31 @@ const parse_string_to_lesson = () => { quiz: quiz, }, }); + } else if (block.includes("{{ Video")) { + let video = block.match(/'([^']+)'/)[1]; + lesson_blocks.push({ + type: "upload", + data: { + file_url: video, + }, + }); + } else if (block.includes("![]")) { + let image = block.match(/\((.*?)\)/)[1]; + lesson_blocks.push({ + type: "upload", + data: { + file_url: image, + }, + }); + } else if (block.includes("#")) { + let level = (block.match(/#/g) || []).length; + lesson_blocks.push({ + type: "header", + data: { + text: block.replace(/#/g, "").trim(), + level: level, + }, + }); } else { lesson_blocks.push({ type: "paragraph", @@ -46,26 +100,6 @@ const parse_string_to_lesson = () => { 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_to_string(outputData); @@ -79,6 +113,15 @@ const parse_lesson_to_string = (data) => { lesson_content += `{{ YouTubeVideo("${block.data.youtube}") }}\n`; } else if (block.type == "quiz") { lesson_content += `{{ Quiz("${block.data.quiz}") }}\n`; + } else if (block.type == "upload") { + let url = block.data.file_url; + lesson_content += block.data.is_video + ? `{{ Video("${url}") }}\n` + : `![](${url})`; + } else if (block.type == "header") { + console.log(block); + lesson_content += + "#".repeat(block.data.level) + ` ${block.data.text}\n`; } else if (block.type == "paragraph") { lesson_content += `${block.data.text}\n`; } @@ -95,7 +138,7 @@ const save = (lesson_content) => { title: $("#lesson-title").val(), body: lesson_content, chapter: $("#lesson-title").data("chapter"), - preview: 0, + preview: $("#preview").prop("checked") ? 1 : 0, idx: $("#lesson-title").data("index"), lesson: lesson ? lesson : "", }, @@ -120,6 +163,12 @@ const fetch_quiz_list = () => { }); }; +const is_video = (url) => { + let video_types = ["mov", "mp4", "mkv"]; + let video_extension = url.split(".").pop(); + return video_types.indexOf(video_extension) >= 0; +}; + class YouTubeVideo { constructor({ data }) { this.data = data; @@ -242,29 +291,58 @@ class Quiz { } } -class Video { +class Upload { static get toolbox() { return { - title: "Video", + title: "Upload", }; } + constructor({ data }) { + this.data = data; + } + render() { this.wrapper = document.createElement("div"); + if (this.data && this.data.file_url) { + $(this.wrapper).html(this.render_upload(this.data.file_url)); + } else { + this.render_upload_dialog(); + } + return this.wrapper; + } + + render_upload_dialog() { + let self = this; new frappe.ui.FileUploader({ disable_file_browser: true, folder: "Home/Attachments", make_attachments_public: true, restrictions: { - allowed_file_types: ["video/*"], + allowed_file_types: ["image/*", "video/*"], }, on_success: (file_doc) => { - $(e.target) - .parent() - .siblings("img") - .addClass("image-preview") - .attr("src", file_doc.file_url); + self.file_url = file_doc.file_url; + $(self.wrapper).html(self.render_upload(self.file_url)); }, }); } + + render_upload(url) { + this.is_video = is_video(url); + if (this.is_video) { + return ``; + } else { + return ``; + } + } + + save(block_content) { + return { + file_url: this.data.file_url || this.file_url, + is_video: this.is_video, + }; + } } diff --git a/lms/www/batch/edit.py b/lms/www/batch/edit.py index 6934e069..88256179 100644 --- a/lms/www/batch/edit.py +++ b/lms/www/batch/edit.py @@ -10,6 +10,7 @@ def get_context(context): lesson_index = frappe.form_dict.get("lesson") lesson_number = f"{chapter_index}.{lesson_index}" context.lesson_index = lesson_index + context.lesson_number = lesson_number context.chapter = frappe.db.get_value( "Chapter Reference", {"idx": chapter_index, "parent": context.course.name}, "chapter" ) diff --git a/lms/www/batch/learn.html b/lms/www/batch/learn.html index 0f270bb2..21861494 100644 --- a/lms/www/batch/learn.html +++ b/lms/www/batch/learn.html @@ -81,7 +81,9 @@ {% if (is_instructor or has_course_moderator_role()) %} - + + {{ _("Edit") }} + {% endif %}
diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 03873329..7a67b834 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -78,10 +78,6 @@ frappe.ready(() => { mark_active_question(); }); - $(".btn-edit").click((e) => { - window.location.href = `${window.location.href}?edit=1`; - }); - $(".btn-back").click((e) => { window.location.href = window.location.href.split("?")[0]; }); diff --git a/lms/www/batch/learn.py b/lms/www/batch/learn.py index 98161f6c..077b3ba1 100644 --- a/lms/www/batch/learn.py +++ b/lms/www/batch/learn.py @@ -16,6 +16,7 @@ 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_number = lesson_number context.lesson_index = lesson_index context.chapter = frappe.db.get_value( "Chapter Reference", {"idx": chapter_index, "parent": context.course.name}, "chapter" diff --git a/lms/www/courses/create.html b/lms/www/courses/create.html index c1620f36..757d3788 100644 --- a/lms/www/courses/create.html +++ b/lms/www/courses/create.html @@ -6,7 +6,7 @@ {% block content %}
{{ Header() }} -
+
{{ CreateCourse() }}
@@ -15,11 +15,17 @@ {% macro Header() %}
-
+
+ {% if course.name %} + + {{ _("Preview") }} + + {% endif %} +
{{ _("Course Details") }}
diff --git a/lms/www/courses/create.js b/lms/www/courses/create.js index 74e5fead..e1aada88 100644 --- a/lms/www/courses/create.js +++ b/lms/www/courses/create.js @@ -92,9 +92,7 @@ const make_editor = () => { ], body: $("#description").get(0), }); - console.log(this.description); this.description.make(); - console.log(this.description); $("#description .form-section:last").removeClass("empty-section"); $("#description .frappe-control").removeClass("hide-control"); $("#description .form-column").addClass("p-0"); diff --git a/lms/www/courses/index.html b/lms/www/courses/index.html index 7dd47f4b..a9713a9d 100644 --- a/lms/www/courses/index.html +++ b/lms/www/courses/index.html @@ -32,7 +32,7 @@ {% endif %} {% if show_creators_section %} - + {{ _("Create a Course") }} {% endif %} diff --git a/lms/www/courses/outline.html b/lms/www/courses/outline.html index b0341d8a..85b56ec0 100644 --- a/lms/www/courses/outline.html +++ b/lms/www/courses/outline.html @@ -8,7 +8,7 @@ {% block page_content %}
{{ Header() }} -
+
{% if chapters | length %} {{ Outline(chapters) }} {% else %} @@ -22,8 +22,8 @@ {% macro Header() %}
-
-
--> - + {{ lesson.title }}
@@ -158,7 +158,7 @@ {% macro EmptyState() %} -
+
{{ _("You have not added any chapter yet") }} @@ -167,10 +167,10 @@ {{ _("Create and manage your chapters from here.") }}
-