fix: text editor for lesson
This commit is contained in:
@@ -2,7 +2,6 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from codecs import ignore_errors
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import json
|
import json
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<button class="btn btn-sm btn-secondary btn-save-chapter"
|
<button class="btn btn-sm btn-secondary btn-save-chapter"
|
||||||
data-index="{{ loop.index }}" data-chapter="{{ chapter.name }}"> {{ _('Save') }} </button>
|
data-index="{{ loop.index }}" data-chapter="{{ chapter.name }}"> {{ _('Save') }} </button>
|
||||||
<a class="btn btn-sm btn-secondary btn-lesson ml-4"
|
<a class="btn btn-sm btn-secondary btn-lesson ml-2"
|
||||||
href="/courses/{{ course.name }}/learn/{{loop.index}}.{{ lessons | length + 1 }}?edit=1"> {{ _("New Lesson") }} </a>
|
href="/courses/{{ course.name }}/learn/{{loop.index}}.{{ lessons | length + 1 }}?edit=1"> {{ _("New Lesson") }} </a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -55,9 +55,12 @@
|
|||||||
{% set active = membership.current_lesson == lesson.name %}
|
{% set active = membership.current_lesson == lesson.name %}
|
||||||
<div class="lesson-info {% if active and not course.edit_mode %} active-lesson {% endif %}">
|
<div class="lesson-info {% if active and not course.edit_mode %} active-lesson {% endif %}">
|
||||||
|
|
||||||
{% if membership or lesson.include_in_preview %}
|
{% if membership or lesson.include_in_preview or is_instructor %}
|
||||||
<a class="lesson-links" href="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
|
<a class="lesson-links" data-course="{{ course.name }}"
|
||||||
data-course="{{ course.name }}">
|
{% if is_instructor and not lesson.include_in_preview %}
|
||||||
|
title="{{ _('This lesson is not available for preview. As you are the Instructor of the course only you can see it.') }}"
|
||||||
|
{% endif %}
|
||||||
|
href="{{ get_lesson_url(course.name, lesson.number) }}{% if course.edit_mode and is_instructor %}?edit=1{% endif %}{{course.query_parameter}}">
|
||||||
|
|
||||||
<svg class="icon icon-sm mr-2">
|
<svg class="icon icon-sm mr-2">
|
||||||
<use class="" href="#{{ lesson.icon }}">
|
<use class="" href="#{{ lesson.icon }}">
|
||||||
@@ -73,17 +76,6 @@
|
|||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{% elif is_instructor and not lesson.include_in_preview %}
|
|
||||||
<a class="lesson-links" data-course="{{ course.name }}"
|
|
||||||
title="This lesson is not available for preview. As you are the Instructor of the course only you can see it."
|
|
||||||
href="{{ get_lesson_url(course.name, lesson.number) }}{% if course.edit_mode %}?edit=1{% endif %}{{course.query_parameter}}">
|
|
||||||
|
|
||||||
<svg class="icon icon-sm mr-2">
|
|
||||||
<use class="" href="#icon-lock">
|
|
||||||
</svg>
|
|
||||||
<div>{{ lesson.title }}</div>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="no-preview" title="This lesson is not available for preview" data-course="{{ course.name }}">
|
<div class="no-preview" title="This lesson is not available for preview" data-course="{{ course.name }}">
|
||||||
<div class="lesson-links">
|
<div class="lesson-links">
|
||||||
@@ -108,20 +100,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{ widgets.NoPreviewModal(course=course) }}
|
|
||||||
|
|
||||||
|
|
||||||
<div class="course-home-outline">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- No Preview Modal -->
|
<!-- No Preview Modal -->
|
||||||
|
{{ widgets.NoPreviewModal(course=course) }}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
@@ -139,6 +119,7 @@ frappe.ready(() => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const expand_the_first_chapter = () => {
|
const expand_the_first_chapter = () => {
|
||||||
let elements = $(".course-home-outline .collapse");
|
let elements = $(".course-home-outline .collapse");
|
||||||
elements.each((i, element) => {
|
elements.each((i, element) => {
|
||||||
@@ -149,6 +130,7 @@ const expand_the_first_chapter = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const expand_the_active_chapter = () => {
|
const expand_the_active_chapter = () => {
|
||||||
|
|
||||||
/* Find anchor matching the URL for course details page */
|
/* Find anchor matching the URL for course details page */
|
||||||
@@ -180,12 +162,14 @@ const expand_the_active_chapter = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const show_section = (element) => {
|
const show_section = (element) => {
|
||||||
$(element).addClass("show");
|
$(element).addClass("show");
|
||||||
$(element).siblings(".chapter-title").children(".chapter-icon").css("transform", "rotate(90deg)");
|
$(element).siblings(".chapter-title").children(".chapter-icon").css("transform", "rotate(90deg)");
|
||||||
$(element).siblings(".chapter-title").attr("aria-expanded", true);
|
$(element).siblings(".chapter-title").attr("aria-expanded", true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const rotate_chapter_icon = (e) => {
|
const rotate_chapter_icon = (e) => {
|
||||||
let icon = $(e.currentTarget).children(".chapter-icon");
|
let icon = $(e.currentTarget).children(".chapter-icon");
|
||||||
if (icon.css("transform") == "none") {
|
if (icon.css("transform") == "none") {
|
||||||
@@ -195,6 +179,7 @@ const rotate_chapter_icon = (e) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const show_no_preview_dialog = (e) => {
|
const show_no_preview_dialog = (e) => {
|
||||||
$("#no-preview-modal").modal("show");
|
$("#no-preview-modal").modal("show");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ input[type=checkbox] {
|
|||||||
.wide-button {
|
.wide-button {
|
||||||
padding: 0.5rem 6rem;
|
padding: 0.5rem 6rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
width: inherit;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -1505,7 +1505,7 @@ li {
|
|||||||
outline: none;
|
outline: none;
|
||||||
background-color: var(--bg-light-gray);
|
background-color: var(--bg-light-gray);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
border: 1px dashed var(--gray-400);
|
border: 1px dashed var(--gray-600);
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1555,5 +1555,4 @@ li {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: var(--text-md);
|
font-size: var(--text-md);
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,6 @@ frappe.ready(() => {
|
|||||||
save_chapter(e);
|
save_chapter(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
if ($("#body").length) {
|
|
||||||
make_editor();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -108,9 +104,13 @@ const notify_user = (e) => {
|
|||||||
|
|
||||||
|
|
||||||
const add_chapter = (e) => {
|
const add_chapter = (e) => {
|
||||||
let next_index = $("[data-index]").last().data("index");
|
if ($(".new-chapter").length) {
|
||||||
|
scroll_to_chapter_container();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$(`<div class="chapter-parent chapter-edit">
|
let next_index = $("[data-index]").last().data("index");
|
||||||
|
$(`<div class="chapter-parent chapter-edit new-chapter">
|
||||||
<div contenteditable="true" data-placeholder="${__('Chapter Name')}" class="chapter-title-main"></div>
|
<div contenteditable="true" data-placeholder="${__('Chapter Name')}" class="chapter-title-main"></div>
|
||||||
<div class="small my-2" contenteditable="true" data-placeholder="${__('Short Description')}"
|
<div class="small my-2" contenteditable="true" data-placeholder="${__('Short Description')}"
|
||||||
class="chapter-description"></div>
|
class="chapter-description"></div>
|
||||||
@@ -118,15 +118,18 @@ const add_chapter = (e) => {
|
|||||||
data-index="${next_index}"> ${__('Save')} </button>
|
data-index="${next_index}"> ${__('Save')} </button>
|
||||||
</div>`).insertAfter(`.chapter-parent:last`);
|
</div>`).insertAfter(`.chapter-parent:last`);
|
||||||
|
|
||||||
$(".btn-chapter").attr("disabled", true);
|
scroll_to_chapter_container();
|
||||||
$([document.documentElement, document.body]).animate({
|
|
||||||
scrollTop: $(".chapter-parent:last").offset().top
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
$(".chapter-parent:last").find(".chapter-title-main").focus();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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) => {
|
const save_chapter = (e) => {
|
||||||
let target = $(e.currentTarget);
|
let target = $(e.currentTarget);
|
||||||
let parent = target.closest(".chapter-parent");
|
let parent = target.closest(".chapter-parent");
|
||||||
@@ -146,23 +149,3 @@ const save_chapter = (e) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const make_editor = () => {
|
|
||||||
this.code_field_group = new frappe.ui.FieldGroup({
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
fieldname: "code_md",
|
|
||||||
fieldtype: "Code",
|
|
||||||
options: "Markdown",
|
|
||||||
wrap: true,
|
|
||||||
max_lines: Infinity,
|
|
||||||
min_lines: 20,
|
|
||||||
default: "Jannat Patel",
|
|
||||||
depends_on: 'eval:doc.type=="Markdown"',
|
|
||||||
}
|
|
||||||
],
|
|
||||||
body: $("#body").get(0),
|
|
||||||
});
|
|
||||||
this.code_field_group.make();
|
|
||||||
$("#body .form-section:last").removeClass("empty-section");
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Lesson Content -->
|
<!-- Lesson Content -->
|
||||||
<div class="markdown-source lesson-content-card">
|
<div class="markdown-source lesson-content-card {% if lesson.edit_mode %} mb-0 mt-2 {% endif %} ">
|
||||||
{% if membership or lesson.include_in_preview or is_instructor %}
|
{% if membership or lesson.include_in_preview or is_instructor %}
|
||||||
|
|
||||||
{% if is_instructor and not lesson.include_in_preview and not lesson.edit_mode %}
|
{% if is_instructor and not lesson.include_in_preview and not lesson.edit_mode %}
|
||||||
@@ -135,57 +135,52 @@
|
|||||||
|
|
||||||
{% macro pagination(prev_url, next_url) %}
|
{% macro pagination(prev_url, next_url) %}
|
||||||
<div class="lesson-pagination">
|
<div class="lesson-pagination">
|
||||||
|
<div>
|
||||||
|
{% if prev_url %}
|
||||||
|
<a class="button is-secondary dark-links prev" href="{{ prev_url }}">
|
||||||
|
<img class="mr-2" src="/assets/lms/icons/left-arrow.svg">
|
||||||
|
{{ _("Prev") }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
{% if not is_mentor(course.name, frappe.session.user) and membership %}
|
||||||
{% if prev_url %}
|
{% set progress = get_progress(course.name, lesson.name) %}
|
||||||
<a class="button is-secondary dark-links prev" href="{{ prev_url }}">
|
<div class="custom-checkbox {% if progress == 'Complete' %} hide {% endif %}">
|
||||||
<img class="mr-2" src="/assets/lms/icons/left-arrow.svg">
|
<label class="quiz-label">
|
||||||
{{ _("Prev") }}
|
<input class="mark-progress" type="checkbox" checked>
|
||||||
</a>
|
<img class="empty-checkbox" />
|
||||||
|
<span class="small">{{ _("Mark as complete on moving to the next lesson") }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button is-secondary mark-progress {{ progress }} {% if progress == 'Incomplete' or progress == None %} hide {% endif %}"
|
||||||
|
data-progress="Incomplete">
|
||||||
|
{{ _("Mark as Incomplete") }}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div>
|
||||||
{% if not is_mentor(course.name, frappe.session.user) and membership %}
|
<a class="button is-primary next {% if membership.progress|int == 100 and not next_url %} hide {% endif %}"
|
||||||
{% set progress = get_progress(course.name, lesson.name) %}
|
{% if next_url %} data-href="{{ next_url }}" {% endif %} href="">
|
||||||
<div class="custom-checkbox {% if progress == 'Complete' %} hide {% endif %}">
|
{% if next_url %} {{ _("Next") }} {% else %} {{ _("Mark as Complete") }} {% endif %}
|
||||||
<label class="quiz-label">
|
<img class="ml-2" src="/assets/lms/icons/side-arrow-white.svg">
|
||||||
<input class="mark-progress" type="checkbox" checked>
|
</a>
|
||||||
<img class="empty-checkbox" />
|
</div>
|
||||||
<span class="small">{{ _("Mark as complete on moving to the next lesson") }}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="button is-secondary mark-progress {{ progress }} {% if progress == 'Incomplete' or progress == None %} hide {% endif %}"
|
|
||||||
data-progress="Incomplete">
|
|
||||||
{{ _("Mark as Incomplete") }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a class="button is-primary next {% if membership.progress|int == 100 and not next_url %} hide {% endif %}"
|
|
||||||
{% if next_url %} data-href="{{ next_url }}" {% endif %} href="">
|
|
||||||
{% if next_url %} {{ _("Next") }} {% else %} {{ _("Mark as Complete") }} {% endif %}
|
|
||||||
<img class="ml-2" src="/assets/lms/icons/side-arrow-white.svg">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro EditLesson(lesson) %}
|
{% macro EditLesson(lesson) %}
|
||||||
<div contenteditable="true" data-placeholder="{{ _('Enter the lesson content.') }}"
|
<div id="body" {% if lesson.body %} data-body="{{ lesson.body }}" {% endif %}></div>
|
||||||
> {% if lesson.body %} {{ lesson.body }} {% endif %} </div>
|
|
||||||
|
|
||||||
<div id="body"></div>
|
|
||||||
|
|
||||||
<label class="preview">
|
<label class="preview">
|
||||||
<input {% if lesson.include_in_preview %} checked {% endif %}
|
<input {% if lesson.include_in_preview %} checked {% endif %} type="checkbox"
|
||||||
type="checkbox" id="preview"> {{ _("Show preview of this lesson") }}
|
id="preview"> {{ _("Show preview of this lesson") }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="mt-8">
|
<div class="mt-4">
|
||||||
|
<a class="btn btn-secondary btn-md" href=""> {{ _("Back to Lesson") }} </a>
|
||||||
<button class="btn btn-primary btn-md btn-lesson pull-right"> {{ _("Save") }} </button>
|
<button class="btn btn-primary btn-md btn-lesson pull-right"> {{ _("Save") }} </button>
|
||||||
|
|
||||||
<div class="attachments-parent">
|
<div class="attachments-parent">
|
||||||
@@ -210,6 +205,8 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Discussions Component -->
|
||||||
{% macro Discussions() %}
|
{% macro Discussions() %}
|
||||||
{% set topics_count = frappe.db.count("Discussion Topic",
|
{% set topics_count = frappe.db.count("Discussion Topic",
|
||||||
{"reference_doctype": "Course Lesson", "reference_docname": lesson.name}) %}
|
{"reference_doctype": "Course Lesson", "reference_docname": lesson.name}) %}
|
||||||
@@ -222,17 +219,17 @@
|
|||||||
{% set redirect_to = "/courses/" + course.name %}
|
{% set redirect_to = "/courses/" + course.name %}
|
||||||
{% set empty_state_title = _("Have a doubt?") %}
|
{% set empty_state_title = _("Have a doubt?") %}
|
||||||
{% set empty_state_subtitle = _("Post it here, our mentors will help you out.") %}
|
{% set empty_state_subtitle = _("Post it here, our mentors will help you out.") %}
|
||||||
|
|
||||||
{% include "frappe/templates/discussions/discussions_section.html" %}
|
{% include "frappe/templates/discussions/discussions_section.html" %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
{%- block script %}
|
{%- block script %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var page_context = {{ page_context | tojson }};
|
var page_context = {{ page_context | tojson }};
|
||||||
</script>
|
</script>
|
||||||
|
{{ include_script('controls.bundle.js') }}
|
||||||
{% for ext in page_extensions %}
|
{% for ext in page_extensions %}
|
||||||
{{ ext.render_footer() }}
|
{{ ext.render_footer() }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ frappe.ready(() => {
|
|||||||
$(".active-question").length && quiz_summary();
|
$(".active-question").length && quiz_summary();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($("#body").length) {
|
||||||
|
make_editor();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -479,14 +483,14 @@ const save_lesson = (e) => {
|
|||||||
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": $("#body").find("br").replaceWith("\n\n").end().text(),
|
"body": this.code_field_group.fields_dict["code_md"].last_value,
|
||||||
"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 : ""
|
||||||
},
|
},
|
||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
window.location.reload();
|
window.location.href = window.location.href.split("?")[0];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -518,3 +522,26 @@ const build_attachment_table = (file_doc) => {
|
|||||||
</tr>
|
</tr>
|
||||||
`);
|
`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const make_editor = () => {
|
||||||
|
this.code_field_group = new frappe.ui.FieldGroup({
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldname: "code_md",
|
||||||
|
fieldtype: "Code",
|
||||||
|
options: "Markdown",
|
||||||
|
wrap: true,
|
||||||
|
max_lines: Infinity,
|
||||||
|
min_lines: 20,
|
||||||
|
default: $("#body").data("body"),
|
||||||
|
depends_on: 'eval:doc.type=="Markdown"',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
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");
|
||||||
|
};
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ def get_current_lesson_details(lesson_number, context):
|
|||||||
details_list = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))
|
details_list = list(filter(lambda x: cstr(x.number) == lesson_number, context.lessons))
|
||||||
if not len(details_list):
|
if not len(details_list):
|
||||||
redirect_to_lesson(context.course)
|
redirect_to_lesson(context.course)
|
||||||
return details_list[0]
|
lesson_info = details_list[0]
|
||||||
|
lesson_info.body = lesson_info.body.replace("\"", "'")
|
||||||
|
print(lesson_info)
|
||||||
|
return lesson_info
|
||||||
|
|
||||||
|
|
||||||
def get_url(lesson_number, course):
|
def get_url(lesson_number, course):
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
{{ course.title if course.title else _("New Course") }}
|
{{ course.title if course.title else _("New Course") }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block head_include %}
|
{% block head_include %}
|
||||||
{% include "public/icons/symbol-defs.svg" %}
|
{% include "public/icons/symbol-defs.svg" %}
|
||||||
<link rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
|
<link rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="common-page-style pt-0 pb-0">
|
<div class="common-page-style pt-0 pb-0">
|
||||||
<div class="course-home-top-container">
|
<div class="course-home-top-container">
|
||||||
@@ -118,7 +120,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro%}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
<!-- Overlay -->
|
<!-- Overlay -->
|
||||||
@@ -133,25 +135,7 @@
|
|||||||
<div class="course-overlay-content">
|
<div class="course-overlay-content">
|
||||||
<div class="course-overlay-title"> {{ course.title }} </div>
|
<div class="course-overlay-title"> {{ course.title }} </div>
|
||||||
|
|
||||||
<div id="interest-alert" class="{% if not is_user_interested %} hide {% endif %}">
|
{{ Notes(course) }}
|
||||||
{{ _("You have opted to be notified for this course. You will receive an email when the course becomes available.") }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if certificate_request and not certificate %}
|
|
||||||
<p class="mb-2"> <b>{{ _("Evaluation On: ") }}</b>
|
|
||||||
{{ _("{0} at {1}").format(frappe.utils.format_date(certificate_request.date, "medium"),
|
|
||||||
frappe.utils.format_time(certificate_request.start_time, "short")) }} </p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if course.status == "Under Review" %}
|
|
||||||
<div class="mb-4">
|
|
||||||
{{ _("Your course is currently under review. Once the review is complete, the System Admins will publish it on the website.") }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if no_of_attempts and no_of_attempts >= course.max_attempts %}
|
|
||||||
<p> {{ _("You have exceeded the maximum number of attempts allowed to appear for evaluations of this course.") }} </p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="vertically-center mb-3">
|
<div class="vertically-center mb-3">
|
||||||
<svg class="icon icon-md mr-1">
|
<svg class="icon icon-md mr-1">
|
||||||
@@ -181,73 +165,184 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% set lesson_index = get_lesson_index(membership.current_lesson) if membership and
|
{{ CTASection(course, membership) }}
|
||||||
membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %}
|
|
||||||
|
|
||||||
{% if show_start_learing_cta %}
|
|
||||||
<div class="button wide-button is-primary join-batch" data-course="{{ course.name | urlencode }}">
|
|
||||||
{{ _("Start Learning") }}
|
|
||||||
<img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% elif is_instructor(course.name) and not course.published and course.status == "Under Review" %}
|
|
||||||
<div class="button wide-button is-primary" id="submit-for-review" data-course="{{ course.name | urlencode }}">
|
|
||||||
{{ _("Submit for Review") }}
|
|
||||||
<img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% elif is_instructor(course.name) and lesson_index %}
|
|
||||||
<a class="button wide-button is-primary" id="continue-learning"
|
|
||||||
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
|
|
||||||
{{ _("Checkout Course") }} <img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% elif course.upcoming and not is_user_interested %}
|
|
||||||
<div class="button wide-button is-default notify-me" data-course="{{course.name | urlencode}}">
|
|
||||||
{{ _("Notify me when available") }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% elif is_cohort_staff(course.name, frappe.session.user) %}
|
|
||||||
<a class="button wide-button is-secondary"
|
|
||||||
href="/courses/{{course.name}}/manage"
|
|
||||||
style="color: inherit;">
|
|
||||||
{{ _("Manage the course") }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% elif membership %}
|
|
||||||
<a class="button wide-button is-primary" id="continue-learning"
|
|
||||||
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
|
|
||||||
{{ _("Continue Learning") }} <img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% set progress = frappe.utils.cint(membership.progress) %}
|
|
||||||
|
|
||||||
{% if membership and course.enable_certification %}
|
|
||||||
{% if certificate %}
|
|
||||||
<a class="button wide-button is-secondary mt-3" href="/courses/{{ course.name }}/{{ certificate }}">
|
|
||||||
{{ _("Get Certificate") }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% elif eligible_for_evaluation %}
|
|
||||||
<a class="button wide-button is-secondary mt-3" id="apply-certificate" data-course="{{ course.name }}">
|
|
||||||
{{ _("Apply for Certificate") }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{% elif course.grant_certificate_after == "Completion" and progress == 100 %}
|
|
||||||
<div class="button wide-button is-secondary mt-3" id="certification" data-course="{{ course.name }}">
|
|
||||||
{{ _("Get Certificate") }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if is_instructor(course.name) %}
|
|
||||||
<a class="btn btn-secondary btn-block" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{ SlotModal(course) }}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
{% macro Description(course) %}
|
||||||
|
<div class="course-description-section" {% if course.edit_mode %} style="min-height: 100px" {% endif %}
|
||||||
|
{% if course.edit_mode %} contenteditable="true" {% endif %} id="description"
|
||||||
|
data-placeholder="Description">{% if course.description %}{{ frappe.utils.md_to_html(course.description) }}{% endif %}</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Save -->
|
||||||
|
{% macro Save(course) %}
|
||||||
|
{% if course.edit_mode %}
|
||||||
|
<div class="my-4">
|
||||||
|
<button class="btn btn-primary btn-md btn-save-course">
|
||||||
|
{{ _("Save Course Details") }} </button>
|
||||||
|
<a class="btn btn-secondary btn-md btn-exit-edit ml-2" href="/courses/{{ course.name }}">
|
||||||
|
{{ _("Back to Course") }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% macro CourseCreator(course) %}
|
||||||
|
<div class="course-home-headings"> {{ _("Course Creators") }} </div>
|
||||||
|
|
||||||
|
<div class="common-card-style course-creators-card">
|
||||||
|
{% set instructors = get_instructors(course.name) %}
|
||||||
|
{% for instructor in instructors %}
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
{{ widgets.Avatar(member=instructor, avatar_class="avatar-medium") }}
|
||||||
|
<div class="ml-4">
|
||||||
|
<div class="course-creator-name"> {{ instructor.full_name }} </div>
|
||||||
|
<div class="course-meta"> {{ get_authored_courses(instructor.name) | length }} {{ _("Courses Created") }} </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Related Courses Section -->
|
||||||
|
{% macro RelatedCourses(course) %}
|
||||||
|
{% if course.related_courses | length %}
|
||||||
|
<div class="related-courses">
|
||||||
|
<div class="container">
|
||||||
|
<div class="course-home-headings"> {{ _("Other Courses") }} </div>
|
||||||
|
<div class="carousel slide" id="carouselExampleControls" data-ride="carousel" data-interval="false">
|
||||||
|
<div class="carousel-inner">
|
||||||
|
{% for crs in course.related_courses %}
|
||||||
|
{% if loop.index % 3 == 1 %}
|
||||||
|
<div class="carousel-item {% if loop.index == 1 %} active {% endif %}"><div class="cards-parent">
|
||||||
|
{% endif %}
|
||||||
|
{{ widgets.CourseCard(course=crs, read_only=False) }}
|
||||||
|
{% if loop.index % 3 == 0 or loop.index == course.related_courses | length %} </div> </div> {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if course.related_courses | length > 3 %}
|
||||||
|
<div class="slider-controls">
|
||||||
|
<a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
|
||||||
|
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
|
||||||
|
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif%}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- CTA's -->
|
||||||
|
{% macro CTASection(course, membership) %}
|
||||||
|
{% set lesson_index = get_lesson_index(membership.current_lesson) if membership and
|
||||||
|
membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %}
|
||||||
|
|
||||||
|
{% if show_start_learing_cta %}
|
||||||
|
<div class="btn btn-primary wide-button join-batch" data-course="{{ course.name | urlencode }}">
|
||||||
|
{{ _("Start Learning") }}
|
||||||
|
<img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% elif is_instructor(course.name) and not course.published and course.status != "Under Review" %}
|
||||||
|
<div class="btn btn-primary wide-button mb-2" id="submit-for-review" data-course="{{ course.name | urlencode }}">
|
||||||
|
{{ _("Submit for Review") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% elif is_instructor(course.name) and lesson_index %}
|
||||||
|
<a class="btn btn-primary wide-button" id="continue-learning"
|
||||||
|
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
|
||||||
|
{{ _("Checkout Course") }} <img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% elif course.upcoming and not is_user_interested %}
|
||||||
|
<div class="btn btn-secondary wide-button notify-me" data-course="{{course.name | urlencode}}">
|
||||||
|
{{ _("Notify me when available") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% elif is_cohort_staff(course.name, frappe.session.user) %}
|
||||||
|
<a class="btn btn-secondary button-links wide-button" href="/courses/{{course.name}}/manage">
|
||||||
|
{{ _("Manage the course") }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% elif membership %}
|
||||||
|
<a class="btn btn-primary wide-button" id="continue-learning"
|
||||||
|
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
|
||||||
|
{{ _("Continue Learning") }} <img class="ml-2" src="/assets/lms/icons/white-arrow.svg" />
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set progress = frappe.utils.cint(membership.progress) %}
|
||||||
|
|
||||||
|
{% if membership and course.enable_certification %}
|
||||||
|
{% if certificate %}
|
||||||
|
<a class="btn btn-secondary wide-button mt-3" href="/courses/{{ course.name }}/{{ certificate }}">
|
||||||
|
{{ _("Get Certificate") }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% elif eligible_for_evaluation %}
|
||||||
|
<a class="btn btn-secondary wide-button mt-3" id="apply-certificate" data-course="{{ course.name }}">
|
||||||
|
{{ _("Apply for Certificate") }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% elif course.grant_certificate_after == "Completion" and progress == 100 %}
|
||||||
|
<div class="btn btn-secondary wide-button is-secondary mt-3" id="certification" data-course="{{ course.name }}">
|
||||||
|
{{ _("Get Certificate") }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_instructor(course.name) %}
|
||||||
|
<a class="btn btn-secondary wide-button" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Notes and Messages -->
|
||||||
|
{% macro Notes(course) %}
|
||||||
|
<div id="interest-alert" class="{% if not is_user_interested %} hide {% endif %}">
|
||||||
|
{{ _("You have opted to be notified for this course. You will receive an email when the course becomes available.") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if certificate_request and not certificate %}
|
||||||
|
<p class="mb-2"> <b>{{ _("Evaluation On: ") }}</b>
|
||||||
|
{{ _("{0} at {1}").format(frappe.utils.format_date(certificate_request.date, "medium"),
|
||||||
|
frappe.utils.format_time(certificate_request.start_time, "short")) }} </p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if course.status == "Under Review" %}
|
||||||
|
<div class="mb-4">
|
||||||
|
{{ _("Your course is currently under review. Once the review is complete, the System Admins will publish it on the website.") }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if no_of_attempts and no_of_attempts >= course.max_attempts %}
|
||||||
|
<p> {{ _("You have exceeded the maximum number of attempts allowed to appear for evaluations of this course.") }} </p>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Modal for Slots -->
|
||||||
|
{% macro SlotModal(course) %}
|
||||||
<div class="modal fade" id="slot-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
<div class="modal fade" id="slot-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -291,76 +386,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Description -->
|
|
||||||
{% macro Description(course) %}
|
|
||||||
<div class="course-description-section" {% if course.edit_mode %} style="min-height: 100px" {% endif %}
|
|
||||||
{% if course.edit_mode %} contenteditable="true" {% endif %} id="description"
|
|
||||||
data-placeholder="Description">{% if course.description %}{{ frappe.utils.md_to_html(course.description) }}{% endif %}</div>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Save -->
|
|
||||||
{% macro Save(course) %}
|
|
||||||
{% if course.edit_mode %}
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-primary btn-md btn-save-course my-4">
|
|
||||||
{{ _("Save Course Details") }} </button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% macro CourseCreator(course) %}
|
|
||||||
<div class="course-home-headings"> {{ _("Course Creators") }} </div>
|
|
||||||
|
|
||||||
<div class="common-card-style course-creators-card">
|
|
||||||
{% set instructors = get_instructors(course.name) %}
|
|
||||||
{% for instructor in instructors %}
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
{{ widgets.Avatar(member=instructor, avatar_class="avatar-medium") }}
|
|
||||||
<div class="ml-4">
|
|
||||||
<div class="course-creator-name"> {{ instructor.full_name }} </div>
|
|
||||||
<div class="course-meta"> {{ get_authored_courses(instructor.name) | length }} {{ _("Courses Created") }} </div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% macro RelatedCourses(course) %}
|
|
||||||
{% if course.related_courses | length %}
|
|
||||||
<div class="related-courses">
|
|
||||||
<div class="container">
|
|
||||||
<div class="course-home-headings"> {{ _("Other Courses") }} </div>
|
|
||||||
<div class="carousel slide" id="carouselExampleControls" data-ride="carousel" data-interval="false">
|
|
||||||
<div class="carousel-inner">
|
|
||||||
{% for crs in course.related_courses %}
|
|
||||||
{% if loop.index % 3 == 1 %}
|
|
||||||
<div class="carousel-item {% if loop.index == 1 %} active {% endif %}"><div class="cards-parent">
|
|
||||||
{% endif %}
|
|
||||||
{{ widgets.CourseCard(course=crs, read_only=False) }}
|
|
||||||
{% if loop.index % 3 == 0 or loop.index == course.related_courses | length %} </div> </div> {% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if course.related_courses | length > 3 %}
|
|
||||||
<div class="slider-controls">
|
|
||||||
<a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
|
|
||||||
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
|
|
||||||
<span class="carousel-control-next-icon" aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endif%}
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|||||||
Reference in New Issue
Block a user