From 0e444ab7d301d93544e43cbdeb130a8e40aad48b Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 10 May 2023 19:35:45 +0530 Subject: [PATCH] test: fixed course creation test --- cypress/e2e/course_creation.cy.js | 63 ++++--- lms/lms/doctype/lms_course/lms_course.json | 3 +- lms/lms/doctype/lms_course/lms_course.py | 7 +- lms/lms/widgets/CourseOutline.html | 8 +- lms/public/css/style.css | 24 +-- lms/public/icons/symbol-defs.svg | 34 +++- lms/public/js/common_functions.js | 137 --------------- lms/www/batch/edit.html | 6 - lms/www/batch/edit.js | 37 +++- lms/www/batch/learn.js | 116 ------------- lms/www/batch/quiz.html | 187 +++++++++++---------- lms/www/batch/quiz.js | 93 +++------- lms/www/batch/quiz_list.html | 21 +-- lms/www/courses/course.js | 149 ---------------- lms/www/courses/create.html | 72 ++++---- lms/www/courses/create.js | 42 ++++- lms/www/courses/outline.html | 2 +- lms/www/courses/outline.js | 11 ++ lms/www/courses/outline.py | 11 +- yarn.lock | 24 +++ 20 files changed, 372 insertions(+), 675 deletions(-) diff --git a/cypress/e2e/course_creation.cy.js b/cypress/e2e/course_creation.cy.js index 87caa7a7..a76bdf8b 100644 --- a/cypress/e2e/course_creation.cy.js +++ b/cypress/e2e/course_creation.cy.js @@ -5,39 +5,50 @@ describe("Course Creation", () => { // Create a course cy.get("a.btn").contains("Create a Course").click(); cy.wait(1000); - cy.url().should("include", "/courses/new-course"); - cy.button("Add Tag").click(); - cy.get(".course-card-pills").type("Test"); + cy.url().should("include", "/courses/new-course/edit"); cy.get("#title").type("Test Course"); cy.get("#intro").type("Test Course Short Introduction"); - cy.get("#video-link").type("-LPmw2Znl2c"); - cy.get("#published").check(); cy.get("#description").type("Test Course Description"); + cy.get("#video-link").type("-LPmw2Znl2c"); + cy.get("#tags-input").type("Test"); + cy.get("#published").check(); cy.wait(1000); - cy.button("Save Course Details").click(); + cy.button("Save").click(); // Add Chapter - cy.wait(3000); - cy.button("New Chapter").click(); - cy.get(".new-chapter .chapter-title-main").type("Test Chapter"); - cy.get(".new-chapter .chapter-description").type( - "Test Chapter Description" - ); - cy.get(".new-chapter .btn-save-chapter").click(); + cy.wait(1000); + cy.link("Course Outline").click(); + + cy.wait(1000); + cy.get(".edit-header .btn-add-chapter").click(); + cy.get("#chapter-title").type("Test Chapter"); + cy.get("#chapter-description").type("Test Chapter Description"); + cy.button("Save").click(); // Add Lesson - cy.wait(3000); - cy.get(".chapter-parent .btn-lesson").click(); - - cy.wait(3000); - cy.get("#title").type("Test Lesson"); - cy.get("#youtube").type("GoDtyItReto"); - cy.get("#body").type("Test Lesson Content"); cy.wait(1000); - cy.get(".btn-lesson").click(); + cy.link("Add Lesson").click(); + cy.wait(1000); + cy.get("#lesson-title").type("Test Lesson"); + + // Content + cy.get(".ce-block").click().type("{enter}"); + cy.get(".ce-toolbar__plus").click(); + cy.get('[data-item-name="youtube"]').click(); + cy.get('input[data-fieldname="youtube"]').type("GoDtyItReto"); + cy.button("Insert").click(); + cy.wait(1000); + + cy.get(".ce-block:last").click().type("{enter}"); + cy.get(".ce-block:last") + .click() + .type( + "This is an extremely big paragraph that is meant to test the UI. This is a very long paragraph. It contains more than once sentence. Its meant to be this long as this is a UI test. Its unbearably long and I'm not sure why I'm typing this much. I'm just going to keep typing until I feel like its long enough. I think its long enough now. I'm going to stop typing now." + ); + cy.button("Save").click(); // View Course - cy.wait(3000); + cy.wait(1000); cy.visit("/courses"); cy.get(".course-card-title:first").contains("Test Course"); cy.get(".course-card:first").click(); @@ -59,7 +70,7 @@ describe("Course Creation", () => { cy.get(".lesson-info:first").click(); // View Lesson - cy.wait(3000); + cy.wait(1000); cy.url().should("include", "learn/1.1"); cy.get("#title").contains("Test Lesson"); cy.get(".lesson-video iframe").should( @@ -67,7 +78,9 @@ describe("Course Creation", () => { "src", "https://www.youtube.com/embed/GoDtyItReto" ); - cy.get(".lesson-content-card").contains("Test Lesson Content"); + cy.get(".lesson-content-card").contains( + "This is an extremely big paragraph that is meant to test the UI. This is a very long paragraph. It contains more than once sentence. Its meant to be this long as this is a UI test. Its unbearably long and I'm not sure why I'm typing this much. I'm just going to keep typing until I feel like its long enough. I think its long enough now. I'm going to stop typing now." + ); // Add Discussion cy.get(".reply").click(); @@ -79,7 +92,7 @@ describe("Course Creation", () => { cy.get(".submit-discussion").click(); // View Discussion - cy.wait(3000); + cy.wait(1000); cy.get(".discussion-topic-title:first").contains("Question Title"); cy.get(".sidebar-parent:first").click(); cy.get(".reply-text").contains( diff --git a/lms/lms/doctype/lms_course/lms_course.json b/lms/lms/doctype/lms_course/lms_course.json index beac3d4e..daeec692 100644 --- a/lms/lms/doctype/lms_course/lms_course.json +++ b/lms/lms/doctype/lms_course/lms_course.json @@ -48,6 +48,7 @@ ], "fields": [ { + "documentation_url": "https://frappe.school", "fieldname": "title", "fieldtype": "Data", "in_list_view": 1, @@ -260,7 +261,7 @@ } ], "make_attachments_public": 1, - "modified": "2023-05-02 09:45:54.826328", + "modified": "2023-05-09 17:08:19.763405", "modified_by": "Administrator", "module": "LMS", "name": "LMS Course", diff --git a/lms/lms/doctype/lms_course/lms_course.py b/lms/lms/doctype/lms_course/lms_course.py index 21bf0093..82075328 100644 --- a/lms/lms/doctype/lms_course/lms_course.py +++ b/lms/lms/doctype/lms_course/lms_course.py @@ -2,7 +2,7 @@ # For license information, please see license.txt import json - +import random import frappe from frappe.model.document import Document from frappe.utils import cint @@ -72,7 +72,10 @@ class LMSCourse(Document): def autoname(self): if not self.name: - self.name = generate_slug(self.title, "LMS Course") + title = self.title + if self.title == "New Course": + title = self.title + str(random.randint(0, 99)) + self.name = generate_slug(title, "LMS Course") def __repr__(self): return f"" diff --git a/lms/lms/widgets/CourseOutline.html b/lms/lms/widgets/CourseOutline.html index ac7ebf0a..a79e4bef 100644 --- a/lms/lms/widgets/CourseOutline.html +++ b/lms/lms/widgets/CourseOutline.html @@ -9,18 +9,18 @@ {{ _("Course Content") }} -
+ {% endif %} {% if chapters | length %} -
+
{% for chapter in chapters %} {% set lessons = get_lessons(course.name, chapter) %} @@ -62,7 +62,7 @@ title="{{ _('This lesson is not available for preview. As you are the Instructor of the course only you can see it.') }}" {% endif %}> - + diff --git a/lms/public/css/style.css b/lms/public/css/style.css index dd4a6429..51e97f51 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -4,6 +4,7 @@ --text-4xl: 36px; --primary-color: var(--gray-900); --primary: var(--gray-900); + --checkbox-gradient: linear-gradient(180deg, #3d4142 -124.51%, var(--primary) 100%); } .nav-link .course-list-count { @@ -28,7 +29,7 @@ .sticky { position: sticky; top: -1px; - z-index: 1020; + z-index: 100; } .is-pinned { @@ -118,6 +119,7 @@ textarea.field-input { .outline-lesson { padding: 0.75rem 0; + border-bottom: 1px solid var(--gray-300); } .common-card-style .outline-lesson:last-of-type { @@ -186,7 +188,7 @@ textarea.field-input { } .drag-handle { - cursor: grabbing; + cursor: move; } .edit-header { @@ -201,6 +203,16 @@ textarea.field-input { border: none; } +.field-label.reqd::after { + content: " *"; + color: var(--red-400); +} + +.error-message { + color: var(--red-500); + font-size: var(--text-sm); +} + body { background-color: #FFFFFF; } @@ -1763,14 +1775,6 @@ li { margin-bottom: 0; } -.quiz-card { - border: 1px solid var(--dark-border-color); - border-radius: var(--border-radius); - padding: 1.25rem; - margin-top: 1.25rem; - font-size: var(--text-base); -} - .option-input { width: 45%; margin-right: 1rem; diff --git a/lms/public/icons/symbol-defs.svg b/lms/public/icons/symbol-defs.svg index cf71d382..f7823137 100644 --- a/lms/public/icons/symbol-defs.svg +++ b/lms/public/icons/symbol-defs.svg @@ -5,19 +5,39 @@ - - - + + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index af50679d..9a5afa3b 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -10,14 +10,6 @@ frappe.ready(() => { notify_user(e); }); - $(".btn-chapter").click((e) => { - add_chapter(e); - }); - - $(document).on("click", ".btn-save-chapter", (e) => { - save_chapter(e); - }); - $(".nav-link").click((e) => { change_hash(e); }); @@ -62,32 +54,6 @@ const pin_header = () => { } }; -const setSortable = (el) => { - new Sortable(el, { - group: { - name: "les", - pull: "les", - put: "les", - }, - onEnd: (e) => { - if ($(e.item).hasClass("lesson-info")) reorder_lesson(e); - else reorder_chapter(e); - }, - onMove: (e) => { - if ( - $(e.dragged).hasClass("lesson-info") && - $(e.to).hasClass("chapter-dropzone") - ) - return false; - if ( - $(e.dragged).hasClass("chapter-edit") && - $(e.to).hasClass("lesson-dropzone") - ) - return false; - }, - }); -}; - const setup_file_size = () => { frappe.provide("frappe.form.formatters"); frappe.form.formatters.FileSize = file_size; @@ -167,65 +133,6 @@ const notify_user = (e) => { }); }; -const add_chapter = (e) => { - if ($(".new-chapter").length) { - scroll_to_chapter_container(); - return; - } - - let next_index = $("[data-index]").last().data("index") + 1 || 1; - let add_after = $(`.chapter-parent:last`).length - ? $(`.chapter-dropzone`) - : $("#outline-heading"); - - $(`
-
-
- -
`).insertAfter(add_after); - - scroll_to_chapter_container(); -}; - -const scroll_to_chapter_container = () => { - $([document.documentElement, document.body]).animate( - { - scrollTop: $(".new-chapter").offset().top, - }, - 1000 - ); - $(".new-chapter").find(".chapter-title-main").focus(); -}; - -const save_chapter = (e) => { - let target = $(e.currentTarget); - let parent = target.closest(".chapter-parent"); - - frappe.call({ - method: "lms.lms.doctype.lms_course.lms_course.save_chapter", - args: { - course: $("#title").data("course"), - title: parent.find(".chapter-title-main").text(), - chapter_description: parent.find(".chapter-description").text(), - idx: target.data("index"), - chapter: parent.data("chapter") ? parent.data("chapter") : "", - }, - callback: (data) => { - frappe.show_alert({ - message: __("Saved"), - indicator: "green", - }); - setTimeout(() => { - window.location.reload(); - }, 1000); - }, - }); -}; - const generate_graph = (chart_name, element, type = "line") => { let date = frappe.datetime; @@ -351,50 +258,6 @@ const show_no_preview_dialog = (e) => { $("#no-preview-modal").modal("show"); }; -const reorder_lesson = (e) => { - let old_chapter = $(e.from).closest(".chapter-edit").data("chapter"); - let new_chapter = $(e.to).closest(".chapter-edit").data("chapter"); - - if (old_chapter == new_chapter && e.oldIndex == e.newIndex) return; - - frappe.call({ - method: "lms.lms.doctype.lms_course.lms_course.reorder_lesson", - args: { - old_chapter: old_chapter, - old_lesson_array: $(e.from) - .children() - .map((i, e) => $(e).data("lesson")) - .get(), - new_chapter: new_chapter, - new_lesson_array: $(e.to) - .children() - .map((i, e) => $(e).data("lesson")) - .get(), - }, - callback: (data) => { - window.location.reload(); - }, - }); -}; - -const reorder_chapter = (e) => { - if (e.oldIndex == e.newIndex) return; - - frappe.call({ - method: "lms.lms.doctype.lms_course.lms_course.reorder_chapter", - args: { - new_index: e.newIndex + 1, - chapter_array: $(e.to) - .children() - .map((i, e) => $(e).data("chapter")) - .get(), - }, - callback: (data) => { - window.location.reload(); - }, - }); -}; - const open_class_dialog = (e) => { this.class_dialog = new frappe.ui.Dialog({ title: __("New Class"), diff --git a/lms/www/batch/edit.html b/lms/www/batch/edit.html index c1b0bcf4..94a97e86 100644 --- a/lms/www/batch/edit.html +++ b/lms/www/batch/edit.html @@ -59,12 +59,6 @@
- - - - - -
{% endmacro %} diff --git a/lms/www/batch/edit.js b/lms/www/batch/edit.js index 9f7dc337..71c81ebc 100644 --- a/lms/www/batch/edit.js +++ b/lms/www/batch/edit.js @@ -122,7 +122,6 @@ const parse_lesson_to_string = (data) => { ? `{{ 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") { @@ -133,6 +132,7 @@ const parse_lesson_to_string = (data) => { }; const save = (lesson_content) => { + validate_mandatory(lesson_content); let lesson = $("#lesson-title").data("lesson"); frappe.call({ @@ -157,6 +157,28 @@ const save = (lesson_content) => { }); }; +const validate_mandatory = (lesson_content) => { + if (!$("#lesson-title").val()) { + let error = $("p") + .addClass("error-message") + .text(__("Please enter a Lesson Title")); + $(error).insertAfter("#lesson-title"); + $("#lesson-title").focus(); + throw "Title is mandatory"; + } + + if (!lesson_content.trim()) { + let error = $("p") + .addClass("error-message") + .text(__("Please enter some content for the lesson")); + $(error).insertAfter("#lesson-content"); + document + .getElementById("lesson-content") + .scrollIntoView({ block: "start" }); + throw "Lesson Content is mandatory"; + } +}; + const fetch_quiz_list = () => { frappe.call({ method: "lms.lms.doctype.lms_quiz.lms_quiz.get_user_quizzes", @@ -205,6 +227,19 @@ class YouTubeVideo { label: __("YouTube Video ID"), reqd: 1, }, + { + fieldname: "instructions_section_break", + fieldtype: "Section Break", + label: __("Instructions:"), + }, + { + fieldname: "instructions", + fieldtype: "HTML", + label: __("Instructions"), + options: __( + "Enter the YouTube Video ID. The ID is the part of the URL after watch?v=. For example, if the URL is https://www.youtube.com/watch?v=QH2-TGUlwu4, the ID is QH2-TGUlwu4" + ), + }, ], primary_action_label: __("Insert"), primary_action(values) { diff --git a/lms/www/batch/learn.js b/lms/www/batch/learn.js index 7a67b834..d70825e1 100644 --- a/lms/www/batch/learn.js +++ b/lms/www/batch/learn.js @@ -1,7 +1,6 @@ frappe.ready(() => { this.marked_as_complete = false; this.quiz_submitted = false; - this.file_type; this.answer = []; this.is_correct = []; let self = this; @@ -12,8 +11,6 @@ frappe.ready(() => { save_current_lesson(); - set_file_type(); - $(".option").click((e) => { enable_check(e); }); @@ -64,14 +61,6 @@ frappe.ready(() => { clear_work(e); }); - $(".btn-lesson").click((e) => { - save_lesson(e); - }); - - $(".add-attachment").click((e) => { - show_upload_modal(); - }); - $(".btn-start-quiz").click((e) => { $("#start-banner").addClass("hide"); $("#quiz-form").removeClass("hide"); @@ -95,16 +84,6 @@ frappe.ready(() => { } }); } - - if ($("#body").length) { - make_editor(); - } - - $("#file-type").change((e) => { - $("#file-type option:selected").each(function () { - self.file_type = $(this).val(); - }); - }); }); const save_current_lesson = () => { @@ -522,98 +501,3 @@ const calculate_and_display_time = (percent_time) => { let progress_color = percent_time < 20 ? "red" : "var(--primary-color)"; $(".timer .progress-bar").css("background-color", progress_color); }; - -const save_lesson = (e) => { - let lesson = $("#title").data("lesson"); - let self = this; - frappe.call({ - method: "lms.lms.doctype.lms_course.lms_course.save_lesson", - args: { - title: $("#title").text(), - body: this.code_field_group.fields_dict["code_md"].value, - youtube: $("#youtube").text(), - quiz_id: $("#quiz-id").text(), - chapter: $("#title").data("chapter"), - preview: $("#preview").prop("checked") ? 1 : 0, - idx: $("#title").data("index"), - lesson: lesson ? lesson : "", - question: $("#assignment-question").text(), - file_type: self.file_type, - }, - callback: (data) => { - frappe.show_alert({ - message: __("Saved"), - indicator: "green", - }); - setTimeout(() => { - window.location.href = window.location.href.split("?")[0]; - }, 1000); - }, - }); -}; - -const show_upload_modal = () => { - new frappe.ui.FileUploader({ - folder: "Home/Attachments", - restrictions: { - allowed_file_types: ["image/*", "video/*"], - }, - on_success: (file_doc) => { - $(".attachments").append(build_attachment_table(file_doc)); - let count = $(".attachment-count").data("count") + 1; - $(".attachment-count").data("count", count); - $(".attachment-count").html(__(`${count} attachments`)); - $(".attachments").removeClass("hide"); - }, - }); -}; - -const build_attachment_table = (file_doc) => { - let video_types = ["mov", "mp4", "mkv"]; - let video_extension = file_doc.file_url.split(".").pop(); - let is_video = video_types.indexOf(video_extension) >= 0; - let link = is_video - ? `{{ Video('${file_doc.file_url}') }}` - : `![](${file_doc.file_url})`; - - return $(` - - ${file_doc.file_name} - - ${__("Copy Link")} - - - - `); -}; - -const make_editor = () => { - /* this.code_field_group = new frappe.ui.FieldGroup({ - fields: [ - { - fieldname: "code_md", - fieldtype: "Text Editor", - default: $(".body-data").html(), - }, - ], - body: $("#body").get(0), - }); - this.code_field_group.make(); - $("#body .form-section:last").removeClass("empty-section"); - $("#body .frappe-control").removeClass("hide-control"); - $("#body .form-column").addClass("p-0"); */ -}; - -const set_file_type = () => { - let self = this; - let file_type = $("#file-type").data("type"); - if (file_type) { - $("#file-type option").each((i, elem) => { - if ($(elem).val() == file_type) { - $(elem).attr("selected", true); - self.file_type = file_type; - } - }); - } -}; diff --git a/lms/www/batch/quiz.html b/lms/www/batch/quiz.html index af335ec1..bdd3a9e3 100644 --- a/lms/www/batch/quiz.html +++ b/lms/www/batch/quiz.html @@ -1,6 +1,6 @@ {% extends "templates/base.html" %} {% block title %} - {{ _("Quiz List") }} + {{ quiz.title if quiz.name else _("Quiz Details") }} {% endblock %} @@ -8,11 +8,25 @@
{{ Header() }}
- {{ QuizCard(quiz) }} + {{ QuizForm(quiz) }}
{% endblock %} +{% macro QuizForm(quiz) %} +
+ {{ QuizDetails(quiz) }} + {% if quiz.questions %} + {% for question in quiz.questions %} + {{ Question(question, loop.index) }} + {% endfor %} + {% endif %} +
+ {{ Question({}, 0) }} +
+
+{% endmacro %} + {% macro Header() %}
@@ -30,104 +44,101 @@
- +
+ + +
+
{% endmacro %} -{% macro QuizCard(quiz) %} -
- -
-
-
-
- {{ _("Title") }} -
-
- {{ _("Give your quiz a title") }} -
+{% macro QuizDetails(quiz) %} +
+
+
+
+ {{ _("Title") }}
-
- +
+ {{ _("Give your quiz a title") }}
-
- - {% if quiz.questions %} - {% for question in quiz.questions %} -
-
-
-
- {{ _("Question") }} {{ loop.index }} -
-
-
- -
-
- -
-
-
- {{ _("Question Type") }} -
-
- - -
-
-
-
- - {% for i in range(1,5) %} - {% set num = frappe.utils.cstr(i) %} - - {% set option = question["option_" + num] %} - {% set explanation = question["explanation_" + num] %} - {% set possible_answer = question["possibility_" + num] %} - -
- -
- - - -
- -
-
- {{ _("Possible Answers") }} {{ num }} -
- -
-
- - - {% endfor %} +
- - - {% endfor %} - {% endif %} -
{% endmacro %} +{% macro Question(question, index) %} +{% set type = question.type if question.type else "Choices" %} +
+
+
+
+ {{ _("Question") }} {{ index }} +
+
+
+ +
+
+
+
+
+ {{ _("Question Type") }} +
+
+ + +
+
+
+ +
+ + {% for i in range(1,5) %} + {% set num = frappe.utils.cstr(i) %} + + {% set option = question["option_" + num] %} + {% set explanation = question["explanation_" + num] %} + {% set possible_answer = question["possibility_" + num] %} + +
+ +
+ + + +
+ +
+
+ {{ _("Possible Answers") }} {{ num }} +
+ +
+
+ + + {% endfor %} +
+
+{% endmacro %} \ No newline at end of file diff --git a/lms/www/batch/quiz.js b/lms/www/batch/quiz.js index 307313b5..47afe84a 100644 --- a/lms/www/batch/quiz.js +++ b/lms/www/batch/quiz.js @@ -1,6 +1,10 @@ frappe.ready(() => { - $(".btn-question").click((e) => { + if ($(".question-card").length <= 1) { add_question(); + } + + $(".btn-add-question").click((e) => { + add_question(true); }); $(".btn-save-question").click((e) => { @@ -11,7 +15,7 @@ frappe.ready(() => { frappe.utils.copy_to_clipboard($(e.currentTarget).data("name")); }); - $(".question-type").click((e) => { + $(document).on("click", ".question-type", (e) => { toggle_form($(e.currentTarget)); }); @@ -43,72 +47,21 @@ const toggle_form = (el) => { } }; -const add_question = () => { - let add_after = $(".quiz-card").length - ? $(".quiz-card:last") - : $("#quiz-title"); - let question_template = `
-
- -
`; - $(question_template).insertAfter(add_after); - get_question_template(); - $(".btn-save-question").removeClass("hide"); +const add_question = (scroll = false) => { + let template = $("#question-template").html(); + let index = $(".question-card:nth-last-child(2)").data("index") + 1 || 1; + template = update_index(template, index); + + $(template).insertBefore($("#question-template")); + scroll && scroll_to_question_container(); }; -const get_question_template = () => { - Array.from({ length: 4 }, (x, num) => { - let option_template = get_option_template(num + 1); - - let add_after = $(".quiz-card:last .option-group").length - ? $(".quiz-card:last .option-group").last() - : $(".type:last"); - question_template = $(option_template).insertAfter(add_after); - }); - - Array.from({ length: 4 }, (x, num) => { - let possibility_template = get_possibility_template(num + 1); - let add_after = $(".quiz-card:last .possibility-group").length - ? $(".quiz-card:last .possibility-group").last() - : $(".quiz-card:last .option-group:last"); - question_template = $(possibility_template).insertAfter(add_after); - }); -}; - -const get_possibility_template = (num) => { - return `
- -
-
-
-
-
-
`; -}; - -const get_option_template = (num) => { - return `
- -
-
-
-
- - -
-
-
`; +const update_index = (template, index) => { + const $template = $(template); + $template.attr("data-index", index); + $template.find(".question-label").text("Question " + index); + $template.find(".question-type input").attr("name", "type-" + index); + return $template.prop("outerHTML"); }; const save_question = (e) => { @@ -124,7 +77,7 @@ const save_question = (e) => { quiz: $("#quiz-title").data("name") || "", }, callback: (data) => { - window.location.reload(); + window.location.href = `/quizzes/${data.message}`; }, }); }; @@ -203,15 +156,15 @@ const validate_mandatory = (details, correct_options, possibilities) => { }; const scroll_to_question_container = () => { - scroll_to_element(".new-quiz-card:last"); - $(".new-quiz-card").find(".question").focus(); + scroll_to_element(".question-card:nth-last-child(2)"); + $(".question-card:nth-last-child(2)").find(".question").focus(); }; const scroll_to_element = (element) => { if ($(element).length) $([document.documentElement, document.body]).animate( { - scrollTop: $(element).offset().top, + scrollTop: $(element).offset().top - 100, }, 1000 ); diff --git a/lms/www/batch/quiz_list.html b/lms/www/batch/quiz_list.html index 74a220c2..2f513831 100644 --- a/lms/www/batch/quiz_list.html +++ b/lms/www/batch/quiz_list.html @@ -35,7 +35,7 @@
{% endmacro %} - -{% block script %} - -{% endblock %} diff --git a/lms/www/courses/course.js b/lms/www/courses/course.js index cd049384..9196bd44 100644 --- a/lms/www/courses/course.js +++ b/lms/www/courses/course.js @@ -1,14 +1,6 @@ frappe.ready(() => { hide_wrapped_mentor_cards(); - $("#cancel-request").click((e) => { - cancel_mentor_request(e); - }); - - $(".view-all-mentors").click((e) => { - view_all_mentors(e); - }); - $(".review-link").click((e) => { show_review_dialog(e); }); @@ -48,30 +40,6 @@ frappe.ready(() => { $(document).on("click", ".slot", (e) => { select_slot(e); }); - - $(".btn-attach").click((e) => { - show_upload_modal(e); - }); - - $(".btn-clear").click((e) => { - clear_image(e); - }); - - $(".btn-tag").click((e) => { - add_tag(e); - }); - - $(".btn-save-course").click((e) => { - save_course(e); - }); - - $(".btn-delete-tag").click((e) => { - remove_tag(e); - }); - - if ($("#description").length) { - make_editor(); - } }); const hide_wrapped_mentor_cards = () => { @@ -92,42 +60,6 @@ const hide_wrapped_mentor_cards = () => { } }; -const cancel_mentor_request = (e) => { - e.preventDefault(); - frappe.call({ - method: "lms.lms.doctype.lms_mentor_request.lms_mentor_request.cancel_request", - args: { - course: decodeURIComponent($(e.currentTarget).attr("data-course")), - }, - callback: (data) => { - if (data.message == "OK") { - $("#mentor-request").removeClass("hide"); - $("#already-applied").addClass("hide"); - } - }, - }); -}; - -const view_all_mentors = (e) => { - $(".wrapped").each((i, element) => { - $(element).slideToggle("slow"); - }); - var text_element = $( - ".view-all-mentors .course-instructor .all-mentors-text" - ); - var text = - text_element.text() == "View all mentors" - ? "View less" - : "View all mentors"; - text_element.text(text); - - if ($(".mentor-icon").css("transform") == "none") { - $(".mentor-icon").css("transform", "rotate(180deg)"); - } else { - $(".mentor-icon").css("transform", ""); - } -}; - const show_review_dialog = (e) => { e.preventDefault(); $("#review-modal").modal("show"); @@ -326,84 +258,3 @@ const close_slot_modal = (e) => { $("#slot-date").val(""); $(".slot-label").addClass("hide"); }; - -const show_upload_modal = () => { - new frappe.ui.FileUploader({ - folder: "Home/Attachments", - restrictions: { - allowed_file_types: ["image/*"], - }, - on_success: (file_doc) => { - $(".course-image-attachment").removeClass("hide"); - $(".course-image-attachment a") - .attr("href", file_doc.file_url) - .text(file_doc.file_url); - $(".btn-attach").addClass("hide"); - }, - }); -}; - -const clear_image = () => { - $(".course-image-attachment").addClass("hide"); - $(".course-image-attachment a").removeAttr("href"); - $(".btn-attach").removeClass("hide"); -}; - -const add_tag = (e) => { - $(`
`).insertBefore(`.btn-tag`); -}; - -const save_course = (e) => { - let tags = $(".course-card-pills") - .map((i, el) => $(el).text().trim()) - .get(); - tags = tags.filter((word) => word.trim().length > 0); - - frappe.call({ - method: "lms.lms.doctype.lms_course.lms_course.save_course", - args: { - tags: tags.join(", "), - title: $("#title").text(), - short_introduction: $("#intro").text(), - video_link: $("#video-link").text(), - image: $("#image").attr("href"), - description: this.code_field_group.fields_dict["code_md"].value, - course: $("#title").data("course") - ? $("#title").data("course") - : "", - published: $("#published").prop("checked") ? 1 : 0, - upcoming: $("#upcoming").prop("checked") ? 1 : 0, - }, - callback: (data) => { - frappe.show_alert({ - message: __("Saved"), - indicator: "green", - }); - setTimeout(() => { - window.location.href = `/courses/${data.message}?edit=1`; - }, 1000); - }, - }); -}; - -const remove_tag = (e) => { - $(e.currentTarget).closest(".course-card-pills").remove(); -}; - -const make_editor = () => { - this.code_field_group = new frappe.ui.FieldGroup({ - fields: [ - { - fieldname: "code_md", - fieldtype: "Text Editor", - default: $(".description-data").html(), - }, - ], - body: $("#description").get(0), - }); - this.code_field_group.make(); - $("#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/create.html b/lms/www/courses/create.html index 2a2a17f1..9e6f07e0 100644 --- a/lms/www/courses/create.html +++ b/lms/www/courses/create.html @@ -46,7 +46,7 @@
-
+
{{ _("Title") }}
@@ -60,21 +60,7 @@
-
- {{ _("Preview Video") }} -
-
- {{ _("A feature video that provides a preview of the course") }} -
-
-
- -
-
- -
-
-
+
{{ _("Short Introduction") }}
@@ -86,6 +72,37 @@
+
+
+
+ {{ _("Course Description") }} +
+
+ {{ _("Add a detailed description") }} +
+
+
+ {% if course.description %} +
+ {{ course.description }} +
+ {% endif %} +
+ +
+
+
+ {{ _("Preview Video ID") }} +
+
+ {{ _("Enter the Preview Video ID. The ID is the part of the URL after watch?v=. For example, if the URL is https://www.youtube.com/watch?v=QH2-TGUlwu4, the ID is QH2-TGUlwu4") }} +
+
+
+ +
+
+
@@ -110,12 +127,12 @@
-
-