Merge pull request #626 from pateljannat/ins-notes-changes
feat: editor js for instructor notes
This commit is contained in:
@@ -33,19 +33,17 @@ describe("Course Creation", () => {
|
|||||||
cy.get("#lesson-title").type("Test Lesson");
|
cy.get("#lesson-title").type("Test Lesson");
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
cy.get(".ce-block").click().type("{enter}");
|
cy.get(".collapse-section.collapsed:first").click();
|
||||||
cy.get(".ce-toolbar__plus").click();
|
cy.get("#lesson-content .ce-block")
|
||||||
cy.get('[data-item-name="youtube"]').click();
|
.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. {enter}"
|
||||||
|
);
|
||||||
|
cy.get("#lesson-content .ce-toolbar__plus").click();
|
||||||
|
cy.get('#lesson-content [data-item-name="youtube"]').click();
|
||||||
cy.get('input[data-fieldname="youtube"]').type("GoDtyItReto");
|
cy.get('input[data-fieldname="youtube"]').type("GoDtyItReto");
|
||||||
cy.button("Insert").click();
|
cy.button("Insert").click();
|
||||||
cy.wait(1000);
|
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();
|
cy.button("Save").click();
|
||||||
|
|
||||||
// View Course
|
// View Course
|
||||||
|
|||||||
@@ -135,13 +135,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "instructor_notes",
|
"fieldname": "instructor_notes",
|
||||||
"fieldtype": "Text",
|
"fieldtype": "Markdown Editor",
|
||||||
"label": "Instructor Notes"
|
"label": "Instructor Notes"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-08-31 21:47:06.314995",
|
"modified": "2023-09-27 15:45:54.738573",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "Course Lesson",
|
"name": "Course Lesson",
|
||||||
|
|||||||
@@ -152,11 +152,6 @@ def get_lesson_details(chapter):
|
|||||||
)
|
)
|
||||||
lesson_details.number = flt(f"{chapter.idx}.{row.idx}")
|
lesson_details.number = flt(f"{chapter.idx}.{row.idx}")
|
||||||
lesson_details.icon = get_lesson_icon(lesson_details.body)
|
lesson_details.icon = get_lesson_icon(lesson_details.body)
|
||||||
if lesson_details.instructor_notes:
|
|
||||||
lesson_details.instructor_notes_html = markdown_to_html(
|
|
||||||
lesson_details.instructor_notes
|
|
||||||
)
|
|
||||||
|
|
||||||
lessons.append(lesson_details)
|
lessons.append(lesson_details)
|
||||||
return lessons
|
return lessons
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,10 @@ textarea.field-input {
|
|||||||
position: unset;
|
position: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.codex-editor--narrow .ce-toolbar__actions {
|
||||||
|
right: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.lesson-editor {
|
.lesson-editor {
|
||||||
border: 1px solid var(--gray-300);
|
border: 1px solid var(--gray-300);
|
||||||
border-radius: var(--border-radius-md);
|
border-radius: var(--border-radius-md);
|
||||||
@@ -2454,3 +2458,15 @@ select {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collapse-section {
|
||||||
|
font-size: var(--text-lg);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-section.collapsed .icon {
|
||||||
|
transition: all 0.5s;
|
||||||
|
-webkit-transform: rotate(180deg);
|
||||||
|
-moz-transform: rotate(180deg);
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
@@ -75,41 +75,54 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<label for="published" class="vertically-center">
|
<label for="preview" class="vertically-center">
|
||||||
<input type="checkbox" id="preview" {% if lesson.include_in_preview %} checked {% endif %}>
|
<input type="checkbox" id="preview" {% if lesson.include_in_preview %} checked {% endif %}>
|
||||||
<span>{{ _("Show preview of this lesson to Guest users.") }}</span>
|
<span>{{ _("Show preview of this lesson to Guest users.") }}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<div class="field-label">
|
<div class="collapse-section collapsed" data-toggle="collapse" data-target="#lesson-content-section">
|
||||||
{{ _("Instructor Notes") }}
|
<svg class="icon icon-sm pull-right">
|
||||||
|
<use href="#icon-up-line"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="field-label">
|
||||||
|
{{ _("Content") }}
|
||||||
|
</div>
|
||||||
|
<div class="field-description mb-2">
|
||||||
|
{{ _("Add your lesson content here") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-description">
|
|
||||||
{{ _("These notes will only be visible to the Course Creator, Course Evaluaor and Moderator.") }}
|
<div id="lesson-content-section" class="collapse">
|
||||||
|
<div id="lesson-content" class="lesson-editor"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="instructor-notes"></div>
|
|
||||||
{% if lesson.instructor_notes %}
|
{% if lesson.body %}
|
||||||
<div id="current-instructor-notes" class="hide">{{ lesson.instructor_notes }}</div>
|
<div id="current-lesson-content" class="hide">{{ lesson.body }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field-group">
|
<div class="field-group">
|
||||||
<div>
|
<div class="collapse-section collapsed" data-toggle="collapse" data-target="#instructor-notes-section">
|
||||||
|
<svg class="icon icon-sm pull-right">
|
||||||
|
<use href="#icon-up-line"></use>
|
||||||
|
</svg>
|
||||||
<div class="field-label">
|
<div class="field-label">
|
||||||
{{ _("Content") }}
|
{{ _("Instructor Notes") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="field-description">
|
<div class="field-description mb-2">
|
||||||
{{ _("Add your lesson content here") }}
|
{{ _("These notes will only be visible to the Course Creator, Course Evaluaor and Moderator.") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="lesson-content" class="lesson-editor"></div>
|
<div id="instructor-notes-section" class="collapse">
|
||||||
{% if lesson.body %}
|
<div id="instructor-notes" class="lesson-editor"></div>
|
||||||
<div id="current-lesson-content" class="hide">{{ lesson.body }}</div>
|
</div>
|
||||||
|
{% if lesson.instructor_notes %}
|
||||||
|
<div id="current-instructor-notes" class="hide">{{ lesson.instructor_notes }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,110 +1,129 @@
|
|||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
frappe.require("controls.bundle.js");
|
||||||
frappe.telemetry.capture("on_lesson_creation_page", "lms");
|
frappe.telemetry.capture("on_lesson_creation_page", "lms");
|
||||||
|
|
||||||
if ($("#instructor-notes").length) {
|
|
||||||
frappe.require("controls.bundle.js", () => {
|
|
||||||
make_instructor_notes_component();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($("#current-lesson-content").length) {
|
if ($("#current-lesson-content").length) {
|
||||||
parse_string_to_lesson();
|
parse_string_to_lesson("lesson");
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_editor();
|
if ($("#current-instructor-notes").length) {
|
||||||
|
parse_string_to_lesson("notes");
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_editor_for_lesson_content();
|
||||||
|
setup_editor_for_instructor_notes();
|
||||||
|
|
||||||
$("#save-lesson").click((e) => {
|
$("#save-lesson").click((e) => {
|
||||||
save_lesson(e);
|
save_lesson(e);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const setup_editor = () => {
|
const setup_editor_for_lesson_content = () => {
|
||||||
self.editor = new EditorJS({
|
self.editor = new EditorJS({
|
||||||
holder: "lesson-content",
|
holder: "lesson-content",
|
||||||
tools: {
|
tools: get_tools(),
|
||||||
embed: {
|
|
||||||
class: Embed,
|
|
||||||
config: {
|
|
||||||
services: {
|
|
||||||
youtube: true,
|
|
||||||
vimeo: true,
|
|
||||||
codepen: true,
|
|
||||||
slides: {
|
|
||||||
regex: /https:\/\/docs\.google\.com\/presentation\/d\/e\/([A-Za-z0-9_-]+)\/pub/,
|
|
||||||
embedUrl:
|
|
||||||
"https://docs.google.com/presentation/d/e/<%= remote_id %>/embed",
|
|
||||||
html: "<iframe width='100%' height='300' frameborder='0' allowfullscreen='true'></iframe>",
|
|
||||||
},
|
|
||||||
pdf: {
|
|
||||||
regex: /(https?:\/\/.*\.pdf)/,
|
|
||||||
embedUrl: "<%= remote_id %>",
|
|
||||||
html: "<iframe width='100%' height='600px' frameborder='0'></iframe>",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
class: Header,
|
|
||||||
inlineToolbar: ["bold", "italic", "link"],
|
|
||||||
config: {
|
|
||||||
levels: [4, 5, 6],
|
|
||||||
defaultLevel: 5,
|
|
||||||
},
|
|
||||||
icon: `<svg class="icon icon-sm" style="">
|
|
||||||
<use class="" href="#icon-header"></use>
|
|
||||||
</svg>`,
|
|
||||||
},
|
|
||||||
paragraph: {
|
|
||||||
class: Paragraph,
|
|
||||||
inlineToolbar: true,
|
|
||||||
config: {
|
|
||||||
preserveBlank: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
youtube: YouTubeVideo,
|
|
||||||
quiz: Quiz,
|
|
||||||
upload: Upload,
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
blocks: self.blocks ? self.blocks : [],
|
blocks: self.lesson_blocks || [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const parse_string_to_lesson = () => {
|
const setup_editor_for_instructor_notes = () => {
|
||||||
let lesson_content = $("#current-lesson-content").html();
|
self.instructor_notes_editor = new EditorJS({
|
||||||
let lesson_blocks = [];
|
holder: "instructor-notes",
|
||||||
|
tools: get_tools(),
|
||||||
|
data: {
|
||||||
|
blocks: self.notes_blocks || [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
lesson_content.split("\n").forEach((block) => {
|
const get_tools = () => {
|
||||||
|
return {
|
||||||
|
embed: {
|
||||||
|
class: Embed,
|
||||||
|
config: {
|
||||||
|
services: {
|
||||||
|
youtube: true,
|
||||||
|
vimeo: true,
|
||||||
|
codepen: true,
|
||||||
|
slides: {
|
||||||
|
regex: /https:\/\/docs\.google\.com\/presentation\/d\/e\/([A-Za-z0-9_-]+)\/pub/,
|
||||||
|
embedUrl:
|
||||||
|
"https://docs.google.com/presentation/d/e/<%= remote_id %>/embed",
|
||||||
|
html: "<iframe width='100%' height='300' frameborder='0' allowfullscreen='true'></iframe>",
|
||||||
|
},
|
||||||
|
pdf: {
|
||||||
|
regex: /(https?:\/\/.*\.pdf)/,
|
||||||
|
embedUrl: "<%= remote_id %>",
|
||||||
|
html: "<iframe width='100%' height='600px' frameborder='0'></iframe>",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
class: Header,
|
||||||
|
inlineToolbar: ["bold", "italic", "link"],
|
||||||
|
config: {
|
||||||
|
levels: [4, 5, 6],
|
||||||
|
defaultLevel: 5,
|
||||||
|
},
|
||||||
|
icon: `<svg class="icon icon-sm" style="">
|
||||||
|
<use class="" href="#icon-header"></use>
|
||||||
|
</svg>`,
|
||||||
|
},
|
||||||
|
paragraph: {
|
||||||
|
class: Paragraph,
|
||||||
|
inlineToolbar: true,
|
||||||
|
config: {
|
||||||
|
preserveBlank: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
youtube: YouTubeVideo,
|
||||||
|
quiz: Quiz,
|
||||||
|
upload: Upload,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const parse_string_to_lesson = (type) => {
|
||||||
|
let content;
|
||||||
|
let blocks = [];
|
||||||
|
|
||||||
|
if (type == "lesson") {
|
||||||
|
content = $("#current-lesson-content").html();
|
||||||
|
} else if (type == "notes") {
|
||||||
|
content = $("#current-instructor-notes").html();
|
||||||
|
}
|
||||||
|
|
||||||
|
content.split("\n").forEach((block) => {
|
||||||
if (block.includes("{{ YouTubeVideo")) {
|
if (block.includes("{{ YouTubeVideo")) {
|
||||||
let youtube_id = block.match(/'([^']+)'/)[1];
|
let youtube_id = block.match(/\(["']([^"']+?)["']\)/)[1];
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "youtube",
|
type: "youtube",
|
||||||
data: {
|
data: {
|
||||||
youtube: youtube_id,
|
youtube: youtube_id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (block.includes("{{ Quiz")) {
|
} else if (block.includes("{{ Quiz")) {
|
||||||
let quiz = block.match(/'([^']+)'/)[1];
|
let quiz = block.match(/\(["']([^"']+?)["']\)/)[1];
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "quiz",
|
type: "quiz",
|
||||||
data: {
|
data: {
|
||||||
quiz: quiz,
|
quiz: quiz,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (block.includes("{{ Video")) {
|
} else if (block.includes("{{ Video")) {
|
||||||
let video = block.match(/'([^']+)'/)[1];
|
let video = block.match(/\(["']([^"']+?)["']\)/)[1];
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "upload",
|
type: "upload",
|
||||||
data: {
|
data: {
|
||||||
file_url: video,
|
file_url: video,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (block.includes("{{ Embed")) {
|
} else if (block.includes("{{ Embed")) {
|
||||||
let embed = block.match(/'([^']+)'/)[1];
|
let embed = block.match(/\(["']([^"']+?)["']\)/)[1];
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "embed",
|
type: "embed",
|
||||||
data: {
|
data: {
|
||||||
service: embed.split("|||")[0],
|
service: embed.split("|||")[0],
|
||||||
@@ -113,7 +132,7 @@ const parse_string_to_lesson = () => {
|
|||||||
});
|
});
|
||||||
} else if (block.includes("![]")) {
|
} else if (block.includes("![]")) {
|
||||||
let image = block.match(/\((.*?)\)/)[1];
|
let image = block.match(/\((.*?)\)/)[1];
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "upload",
|
type: "upload",
|
||||||
data: {
|
data: {
|
||||||
file_url: image,
|
file_url: image,
|
||||||
@@ -121,7 +140,7 @@ const parse_string_to_lesson = () => {
|
|||||||
});
|
});
|
||||||
} else if (block.includes("#")) {
|
} else if (block.includes("#")) {
|
||||||
let level = (block.match(/#/g) || []).length;
|
let level = (block.match(/#/g) || []).length;
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "header",
|
type: "header",
|
||||||
data: {
|
data: {
|
||||||
text: block.replace(/#/g, "").trim(),
|
text: block.replace(/#/g, "").trim(),
|
||||||
@@ -129,7 +148,7 @@ const parse_string_to_lesson = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
lesson_blocks.push({
|
blocks.push({
|
||||||
type: "paragraph",
|
type: "paragraph",
|
||||||
data: {
|
data: {
|
||||||
text: block,
|
text: block,
|
||||||
@@ -138,16 +157,25 @@ const parse_string_to_lesson = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.blocks = lesson_blocks;
|
if (type == "lesson") {
|
||||||
|
this.lesson_blocks = blocks;
|
||||||
|
} else if (type == "notes") {
|
||||||
|
this.notes_blocks = blocks;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const save_lesson = (e) => {
|
const save_lesson = (e) => {
|
||||||
self.editor.save().then((outputData) => {
|
self.editor.save().then((outputData) => {
|
||||||
parse_lesson_to_string(outputData);
|
parse_content_to_string(outputData, "lesson");
|
||||||
|
|
||||||
|
self.instructor_notes_editor.save().then((outputData) => {
|
||||||
|
parse_content_to_string(outputData, "notes");
|
||||||
|
save();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const parse_lesson_to_string = (data) => {
|
const parse_content_to_string = (data, type) => {
|
||||||
let lesson_content = "";
|
let lesson_content = "";
|
||||||
data.blocks.forEach((block) => {
|
data.blocks.forEach((block) => {
|
||||||
if (block.type == "youtube") {
|
if (block.type == "youtube") {
|
||||||
@@ -175,24 +203,28 @@ const parse_lesson_to_string = (data) => {
|
|||||||
}|||${block.data.embed.replace(/&/g, "&")}") }}\n`;
|
}|||${block.data.embed.replace(/&/g, "&")}") }}\n`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
save(lesson_content);
|
if (type == "lesson") {
|
||||||
|
this.lesson_content_data = lesson_content;
|
||||||
|
} else if (type == "notes") {
|
||||||
|
this.instructor_notes_data = lesson_content;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const save = (lesson_content) => {
|
const save = () => {
|
||||||
validate_mandatory(lesson_content);
|
console.log(this.instructor_notes_data);
|
||||||
|
console.log(this.lesson_content_data);
|
||||||
|
validate_mandatory(this.lesson_content_data);
|
||||||
let lesson = $("#lesson-title").data("lesson");
|
let lesson = $("#lesson-title").data("lesson");
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "lms.lms.doctype.lms_course.lms_course.save_lesson",
|
method: "lms.lms.doctype.lms_course.lms_course.save_lesson",
|
||||||
args: {
|
args: {
|
||||||
title: $("#lesson-title").val(),
|
title: $("#lesson-title").val(),
|
||||||
body: lesson_content,
|
body: this.lesson_content_data,
|
||||||
chapter: $("#lesson-title").data("chapter"),
|
chapter: $("#lesson-title").data("chapter"),
|
||||||
preview: $("#preview").prop("checked") ? 1 : 0,
|
preview: $("#preview").prop("checked") ? 1 : 0,
|
||||||
idx: $("#lesson-title").data("index"),
|
idx: $("#lesson-title").data("index"),
|
||||||
lesson: lesson ? lesson : "",
|
lesson: lesson ? lesson : "",
|
||||||
instructor_notes:
|
instructor_notes: this.instructor_notes_data,
|
||||||
this.instructor_notes.get_values().instructor_notes,
|
|
||||||
},
|
},
|
||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
frappe.show_alert({
|
frappe.show_alert({
|
||||||
|
|||||||
@@ -155,13 +155,18 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if lesson.instructor_notes and (is_moderator or instructor or is_evaluator) %}
|
{% if instructor_notes and (is_moderator or instructor or is_evaluator) %}
|
||||||
<div class="alert alert-info mb-4">
|
<div class="alert alert-secondary mb-4">
|
||||||
<div class="bold-heading mb-2">
|
<div class="bold-heading collapse-section collapsed" data-toggle="collapse" data-target="#instructor-notes">
|
||||||
{{ _("Instructor Notes") }}
|
<svg class="icon icon-md pull-right">
|
||||||
|
<use href="#icon-up-line"></use>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
{{ _("Instructor Notes") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="collapse" id="instructor-notes">
|
||||||
{{ lesson.instructor_notes_html }}
|
{{ instructor_notes }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -227,36 +232,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
<!-- Help Article -->
|
|
||||||
{% macro HelpArticle() %}
|
|
||||||
<div class="medium">
|
|
||||||
<h3> {{ _("Embed Components") }} </h3>
|
|
||||||
<p>
|
|
||||||
{{ _("You can add additional content to the lesson using a special syntax. The table below mentions
|
|
||||||
all types of dynamic content that you can add to the lessons and the syntax for the same.") }}
|
|
||||||
</p>
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
<b> {{ _("YouTube Video") }} </b>
|
|
||||||
<p> To get the YouTube Video ID, follow the steps mentioned below. </p>
|
|
||||||
<ul class="px-4">
|
|
||||||
<li>
|
|
||||||
{{ _("Upload the video on youtube.") }}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
{{ _("When you share a youtube video, it shows a URL") }}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
{{ _("Copy the last parameter of the URL and paste it here.") }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Discussions Component -->
|
<!-- Discussions Component -->
|
||||||
{% macro Discussions() %}
|
{% macro Discussions() %}
|
||||||
{% set topics_count = frappe.db.count("Discussion Topic", {
|
{% set topics_count = frappe.db.count("Discussion Topic", {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import cstr, flt
|
from frappe.utils import cstr, flt
|
||||||
|
from lms.lms.md import markdown_to_html
|
||||||
|
|
||||||
from lms.lms.utils import (
|
from lms.lms.utils import (
|
||||||
get_lesson_url,
|
get_lesson_url,
|
||||||
@@ -46,6 +47,9 @@ def get_context(context):
|
|||||||
context.is_moderator = has_course_moderator_role()
|
context.is_moderator = has_course_moderator_role()
|
||||||
context.is_evaluator = has_course_evaluator_role()
|
context.is_evaluator = has_course_evaluator_role()
|
||||||
|
|
||||||
|
if context.lesson.instructor_notes:
|
||||||
|
context.instructor_notes = markdown_to_html(context.lesson.instructor_notes)
|
||||||
|
|
||||||
context.show_lesson = (
|
context.show_lesson = (
|
||||||
context.membership
|
context.membership
|
||||||
or (context.lesson and context.lesson.include_in_preview)
|
or (context.lesson and context.lesson.include_in_preview)
|
||||||
|
|||||||
@@ -172,6 +172,7 @@
|
|||||||
|
|
||||||
|
|
||||||
{% macro CourseList(courses) %}
|
{% macro CourseList(courses) %}
|
||||||
|
{% if courses | length or is_moderator %}
|
||||||
<div class="batch-course-list">
|
<div class="batch-course-list">
|
||||||
|
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
@@ -215,6 +216,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user