fix: text editor for lesson

This commit is contained in:
Jannat Patel
2022-08-12 09:09:50 +05:30
parent 301664ce93
commit 64dc76d616
8 changed files with 282 additions and 266 deletions

View File

@@ -2,7 +2,6 @@
# For license information, please see license.txt
from __future__ import unicode_literals
from codecs import ignore_errors
import frappe
from frappe.model.document import Document
import json

View File

@@ -37,7 +37,7 @@
<div class="mt-2">
<button class="btn btn-sm btn-secondary btn-save-chapter"
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>
</div>
{% endif %}
@@ -55,9 +55,12 @@
{% set active = membership.current_lesson == lesson.name %}
<div class="lesson-info {% if active and not course.edit_mode %} active-lesson {% endif %}">
{% if membership or lesson.include_in_preview %}
<a class="lesson-links" href="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}">
{% if membership or lesson.include_in_preview or is_instructor %}
<a class="lesson-links" 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">
<use class="" href="#{{ lesson.icon }}">
@@ -73,17 +76,6 @@
</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 %}
<div class="no-preview" title="This lesson is not available for preview" data-course="{{ course.name }}">
<div class="lesson-links">
@@ -108,20 +100,8 @@
{% endif %}
</div>
{{ widgets.NoPreviewModal(course=course) }}
<div class="course-home-outline">
</div>
<!-- No Preview Modal -->
{{ widgets.NoPreviewModal(course=course) }}
<script>
@@ -139,6 +119,7 @@ frappe.ready(() => {
});
const expand_the_first_chapter = () => {
let elements = $(".course-home-outline .collapse");
elements.each((i, element) => {
@@ -149,6 +130,7 @@ const expand_the_first_chapter = () => {
});
};
const expand_the_active_chapter = () => {
/* Find anchor matching the URL for course details page */
@@ -180,12 +162,14 @@ const expand_the_active_chapter = () => {
}
};
const show_section = (element) => {
$(element).addClass("show");
$(element).siblings(".chapter-title").children(".chapter-icon").css("transform", "rotate(90deg)");
$(element).siblings(".chapter-title").attr("aria-expanded", true);
};
const rotate_chapter_icon = (e) => {
let icon = $(e.currentTarget).children(".chapter-icon");
if (icon.css("transform") == "none") {
@@ -195,6 +179,7 @@ const rotate_chapter_icon = (e) => {
}
};
const show_no_preview_dialog = (e) => {
$("#no-preview-modal").modal("show");
};

View File

@@ -329,7 +329,7 @@ input[type=checkbox] {
.wide-button {
padding: 0.5rem 6rem;
font-weight: 500;
width: inherit;
width: 100%;
}
@media (max-width: 768px) {
@@ -1505,7 +1505,7 @@ li {
outline: none;
background-color: var(--bg-light-gray);
border-radius: var(--border-radius);
border: 1px dashed var(--gray-400);
border: 1px dashed var(--gray-600);
padding: 0.5rem 0.75rem;
}
@@ -1555,5 +1555,4 @@ li {
display: flex;
align-items: center;
font-size: var(--text-md);
margin-top: 1rem;
}

View File

@@ -20,10 +20,6 @@ frappe.ready(() => {
save_chapter(e);
});
if ($("#body").length) {
make_editor();
}
});
@@ -108,9 +104,13 @@ const notify_user = (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 class="small my-2" contenteditable="true" data-placeholder="${__('Short Description')}"
class="chapter-description"></div>
@@ -118,15 +118,18 @@ const add_chapter = (e) => {
data-index="${next_index}"> ${__('Save')} </button>
</div>`).insertAfter(`.chapter-parent:last`);
$(".btn-chapter").attr("disabled", true);
$([document.documentElement, document.body]).animate({
scrollTop: $(".chapter-parent:last").offset().top
}, 1000);
$(".chapter-parent:last").find(".chapter-title-main").focus();
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");
@@ -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");
}

View File

@@ -102,7 +102,7 @@
</div>
<!-- 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 is_instructor and not lesson.include_in_preview and not lesson.edit_mode %}
@@ -135,57 +135,52 @@
{% macro pagination(prev_url, next_url) %}
<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 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>
{% if not is_mentor(course.name, frappe.session.user) and membership %}
{% set progress = get_progress(course.name, lesson.name) %}
<div class="custom-checkbox {% if progress == 'Complete' %} hide {% endif %}">
<label class="quiz-label">
<input class="mark-progress" type="checkbox" checked>
<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 %}
</div>
{% if not is_mentor(course.name, frappe.session.user) and membership %}
{% set progress = get_progress(course.name, lesson.name) %}
<div class="custom-checkbox {% if progress == 'Complete' %} hide {% endif %}">
<label class="quiz-label">
<input class="mark-progress" type="checkbox" checked>
<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 %}
<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>
<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>
{% endmacro %}
{% macro EditLesson(lesson) %}
<div contenteditable="true" data-placeholder="{{ _('Enter the lesson content.') }}"
> {% if lesson.body %} {{ lesson.body }} {% endif %} </div>
<div id="body"></div>
<div id="body" {% if lesson.body %} data-body="{{ lesson.body }}" {% endif %}></div>
<label class="preview">
<input {% if lesson.include_in_preview %} checked {% endif %}
type="checkbox" id="preview"> {{ _("Show preview of this lesson") }}
<input {% if lesson.include_in_preview %} checked {% endif %} type="checkbox"
id="preview"> {{ _("Show preview of this lesson") }}
</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>
<div class="attachments-parent">
@@ -210,6 +205,8 @@
</div>
{% endmacro %}
<!-- Discussions Component -->
{% macro Discussions() %}
{% set topics_count = frappe.db.count("Discussion Topic",
{"reference_doctype": "Course Lesson", "reference_docname": lesson.name}) %}
@@ -222,17 +219,17 @@
{% set redirect_to = "/courses/" + course.name %}
{% set empty_state_title = _("Have a doubt?") %}
{% set empty_state_subtitle = _("Post it here, our mentors will help you out.") %}
{% include "frappe/templates/discussions/discussions_section.html" %}
{% endmacro %}
<!-- Scripts -->
{%- block script %}
{{ super() }}
<script type="text/javascript">
var page_context = {{ page_context | tojson }};
var page_context = {{ page_context | tojson }};
</script>
{{ include_script('controls.bundle.js') }}
{% for ext in page_extensions %}
{{ ext.render_footer() }}
{% endfor %}

View File

@@ -75,6 +75,10 @@ frappe.ready(() => {
$(".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",
args: {
"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"),
"preview": $("#preview").prop("checked") ? 1 : 0,
"idx": $("#title").data("index"),
"lesson": lesson ? lesson : ""
},
callback: (data) => {
window.location.reload();
window.location.href = window.location.href.split("?")[0];
}
});
};
@@ -518,3 +522,26 @@ const build_attachment_table = (file_doc) => {
</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");
};

View File

@@ -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))
if not len(details_list):
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):

View File

@@ -3,11 +3,13 @@
{{ course.title if course.title else _("New Course") }}
{% endblock %}
{% block head_include %}
{% include "public/icons/symbol-defs.svg" %}
<link rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
{% endblock %}
{% block content %}
<div class="common-page-style pt-0 pb-0">
<div class="course-home-top-container">
@@ -118,7 +120,7 @@
</div>
</div>
{% endif %}
{% endmacro%}
{% endmacro %}
<!-- Overlay -->
@@ -133,25 +135,7 @@
<div class="course-overlay-content">
<div class="course-overlay-title"> {{ course.title }} </div>
<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 %}
{{ Notes(course) }}
<div class="vertically-center mb-3">
<svg class="icon icon-md mr-1">
@@ -181,73 +165,184 @@
</div>
{% endif %}
{% 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="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 %}
{{ CTASection(course, membership) }}
</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-dialog" role="document">
<div class="modal-content">
@@ -291,76 +386,4 @@
</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 %}