feat: lesson editor youtube and quiz components
This commit is contained in:
@@ -140,6 +140,26 @@ textarea.field-input {
|
|||||||
margin: 0 0.5rem;
|
margin: 0 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quiz-modal {
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ce-block__content {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ce-toolbar__content {
|
||||||
|
position: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-editor {
|
||||||
|
border: 1px solid var(--gray-300);
|
||||||
|
border-radius: var(--border-radius-md);
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
@@ -732,7 +752,7 @@ input[type=checkbox] {
|
|||||||
|
|
||||||
.course-content-parent {
|
.course-content-parent {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: 2rem;
|
grid-gap: 4rem;
|
||||||
grid-template-columns: 1fr 3fr;
|
grid-template-columns: 1fr 3fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="lesson-content"></div>
|
<div class="field-group">
|
||||||
|
<div>
|
||||||
|
<div class="field-label">
|
||||||
|
{{ _("Content") }}
|
||||||
|
</div>
|
||||||
|
<div class="field-description">
|
||||||
|
{{ _("Add your lesson content here") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="lesson-content" class="lesson-editor"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
@@ -58,6 +69,21 @@
|
|||||||
|
|
||||||
{%- block script %}
|
{%- block script %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
|
{% if is_moderator %}
|
||||||
|
<script>
|
||||||
|
frappe.boot.user = {
|
||||||
|
"can_create": [],
|
||||||
|
"can_select": ["LMS Quiz"],
|
||||||
|
"can_read": ["LMS Quiz"]
|
||||||
|
};
|
||||||
|
|
||||||
|
frappe.router = {
|
||||||
|
slug (name) {
|
||||||
|
return name.toLowerCase().replace(/ /g, "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
{{ include_script('controls.bundle.js') }}
|
{{ include_script('controls.bundle.js') }}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -20,10 +20,21 @@ const setup_editor = () => {
|
|||||||
|
|
||||||
const save_lesson = (e) => {
|
const save_lesson = (e) => {
|
||||||
self.editor.save().then((outputData) => {
|
self.editor.save().then((outputData) => {
|
||||||
console.log(outputData);
|
parse_lesson(outputData);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetch_quiz_list = () => {
|
||||||
|
frappe.call({
|
||||||
|
method: "lms.lms.doctype.lms_quiz.lms_quiz.get_user_quizzes",
|
||||||
|
callback: (r) => {
|
||||||
|
self.quiz_list = r.message;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const parse_lesson = (data) => {};
|
||||||
|
|
||||||
class YouTubeVideo {
|
class YouTubeVideo {
|
||||||
static get toolbox() {
|
static get toolbox() {
|
||||||
return {
|
return {
|
||||||
@@ -32,18 +43,39 @@ class YouTubeVideo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let self = this;
|
||||||
this.wrapper = document.createElement("div");
|
this.wrapper = document.createElement("div");
|
||||||
$(this.wrapper).html(`<div class="field-group">
|
let youtubedialog = new frappe.ui.Dialog({
|
||||||
<div class="">
|
title: __("YouTube Video"),
|
||||||
<input id="youtube" type="text" class="field-input">
|
fields: [
|
||||||
</div>
|
{
|
||||||
</div>`);
|
fieldname: "youtube",
|
||||||
|
fieldtype: "Data",
|
||||||
|
label: __("YouTube Video ID"),
|
||||||
|
reqd: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primary_action_label: __("Insert"),
|
||||||
|
primary_action(values) {
|
||||||
|
youtubedialog.hide();
|
||||||
|
self.youtube = values.youtube;
|
||||||
|
$(self.wrapper).html(` <iframe width="100%" height="400"
|
||||||
|
src="https://www.youtube.com/embed/${self.youtube}"
|
||||||
|
title="YouTube video player"
|
||||||
|
frameborder="0"
|
||||||
|
style="border-radius: var(--border-radius-lg); margin: 1rem 0;"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowfullscreen>
|
||||||
|
</iframe>`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
youtubedialog.show();
|
||||||
return this.wrapper;
|
return this.wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
save(block_content) {
|
save(block_content) {
|
||||||
return {
|
return {
|
||||||
youtube: $("#youtube").val(),
|
youtube: this.youtube,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,28 +89,68 @@ class Quiz {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.wrapper = document.createElement("div");
|
this.wrapper = document.createElement("div");
|
||||||
$(this.wrapper).html(
|
let self = this;
|
||||||
`<div>
|
let quizdialog = new frappe.ui.Dialog({
|
||||||
<select id="quiz" class="field-input">
|
title: __("Select a Quiz"),
|
||||||
<option value="">Select Quiz</option>
|
fields: [
|
||||||
</select>
|
{
|
||||||
</div>`
|
fieldname: "quiz",
|
||||||
);
|
fieldtype: "Link",
|
||||||
self.quiz_list.forEach((quiz) => {
|
label: __("Quiz"),
|
||||||
$(this.wrapper)
|
reqd: 1,
|
||||||
.find("#quiz")
|
options: "LMS Quiz",
|
||||||
.append(`<option value="${quiz.name}">${quiz.title}</option>`);
|
},
|
||||||
|
],
|
||||||
|
primary_action_label: __("Insert"),
|
||||||
|
primary_action(values) {
|
||||||
|
self.quiz = values.quiz;
|
||||||
|
quizdialog.hide();
|
||||||
|
$(self.wrapper).html(
|
||||||
|
`<div class="common-card-style p-2 my-2 bold-heading">
|
||||||
|
Quiz: ${self.quiz}
|
||||||
|
</div>`
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
quizdialog.show();
|
||||||
|
setTimeout(() => {
|
||||||
|
$(".modal-body").css("min-height", "300px");
|
||||||
|
$(".modal-body input").focus();
|
||||||
|
}, 1000);
|
||||||
return this.wrapper;
|
return this.wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
save(block_content) {
|
||||||
|
return {
|
||||||
|
quiz: this.quiz,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetch_quiz_list = () => {
|
class Video {
|
||||||
frappe.call({
|
static get toolbox() {
|
||||||
method: "lms.lms.doctype.lms_quiz.lms_quiz.get_user_quizzes",
|
return {
|
||||||
callback: (r) => {
|
title: "Video",
|
||||||
self.quiz_list = r.message;
|
};
|
||||||
},
|
}
|
||||||
});
|
|
||||||
};
|
render() {
|
||||||
|
this.wrapper = document.createElement("div");
|
||||||
|
let self = this;
|
||||||
|
new frappe.ui.FileUploader({
|
||||||
|
disable_file_browser: true,
|
||||||
|
folder: "Home/Attachments",
|
||||||
|
make_attachments_public: true,
|
||||||
|
restrictions: {
|
||||||
|
allowed_file_types: ["video/*"],
|
||||||
|
},
|
||||||
|
on_success: (file_doc) => {
|
||||||
|
$(e.target)
|
||||||
|
.parent()
|
||||||
|
.siblings("img")
|
||||||
|
.addClass("image-preview")
|
||||||
|
.attr("src", file_doc.file_url);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import frappe
|
import frappe
|
||||||
from lms.www.utils import get_current_lesson_details, get_common_context
|
from lms.www.utils import get_current_lesson_details, get_common_context
|
||||||
|
from lms.lms.utils import is_instructor, has_course_moderator_role
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
@@ -8,3 +10,8 @@ def get_context(context):
|
|||||||
lesson_index = frappe.form_dict.get("lesson")
|
lesson_index = frappe.form_dict.get("lesson")
|
||||||
lesson_number = f"{chapter_index}.{lesson_index}"
|
lesson_number = f"{chapter_index}.{lesson_index}"
|
||||||
context.lesson = get_current_lesson_details(lesson_number, context, True)
|
context.lesson = get_current_lesson_details(lesson_number, context, True)
|
||||||
|
context.is_moderator = has_course_moderator_role()
|
||||||
|
instructor = is_instructor(context.course.name)
|
||||||
|
|
||||||
|
if not instructor and not has_course_moderator_role():
|
||||||
|
raise frappe.PermissionError(_("You do not have permission to access this page."))
|
||||||
|
|||||||
Reference in New Issue
Block a user