feat: added learn page
- added sections to the lesson to handle multiple sesions like examples and exercises - added livecode integration to lesson pages - autosave and submiting the answers is not done yet
This commit is contained in:
@@ -14,10 +14,12 @@
|
||||
<div class="batch-header">
|
||||
{{ BatchHearder(course.name, member_count) }}
|
||||
</div>
|
||||
<div class="message-section">
|
||||
{{ Messages(messages) }}
|
||||
<div class="messages">
|
||||
<div class="message-section">
|
||||
{{ Messages(messages) }}
|
||||
</div>
|
||||
{{ TextArea() }}
|
||||
</div>
|
||||
{{ TextArea() }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -44,4 +46,4 @@
|
||||
<input type="text" class="msger-input" placeholder="Write your message...">
|
||||
<button type="submit" class="msger-send-btn" data-batch="{{batch.name | urlencode }}">Send</button>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,13 +1,106 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% block title %}Learn{% endblock %}
|
||||
{% from "www/macros/livecode.html" import LiveCodeEditorJS, LiveCodeEditor with context %}
|
||||
{% block title %}{{ lesson.title }}{% endblock %}
|
||||
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Courses" />
|
||||
<meta name="keywords" content="" />
|
||||
<meta name="description" content="{{lesson.title}} - {{course.title}}" />
|
||||
<meta name="keywords" content="{{lesson.title}} - {{course.title}}" />
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="{{ livecode_url }}/static/codemirror/lib/codemirror.css">
|
||||
<link rel="stylesheet" href="/assets/css/lms.css">
|
||||
|
||||
<script src="{{ livecode_url }}/static/codemirror/lib/codemirror.js"></script>
|
||||
<script src="{{ livecode_url }}/static/codemirror/mode/python/python.js"></script>
|
||||
<script src="{{ livecode_url }}/static/codemirror/keymap/sublime.js"></script>
|
||||
|
||||
<script src="{{ livecode_url }}/static/codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script src="{{ livecode_url }}/static/codemirror/addon/comment/comment.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course.name, batch.name) }}
|
||||
<div class="container">
|
||||
<div class="container lesson">
|
||||
|
||||
<h1>{{ lesson.title }} - {{ lesson.name }}</h1>
|
||||
|
||||
{% for s in lesson.get_sections() %}
|
||||
<div class="section section-{{ s.type }}">
|
||||
{{ render_section(s) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% macro render_section(s) %}
|
||||
{% if s.type == "text" %}
|
||||
{{ render_section_text(s) }}
|
||||
{% elif s.type == "example" or s.type == "code" or s.type == "exercise" %}
|
||||
{{ LiveCodeEditor(s.name, s.get_latest_code_for_user(), s.type=="exercise", "2 hours ago") }}
|
||||
{% else %}
|
||||
<div>Unknown section type: {{s.type}}</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_section_text(s) %}
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
{{ frappe.utils.md_to_html(s.contents) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{%- block script %}
|
||||
{{ super() }}
|
||||
{{ LiveCodeEditorJS() }}
|
||||
|
||||
|
||||
<!-- <script type="text/javascript">
|
||||
$(function() {
|
||||
var editorLookup = {};
|
||||
|
||||
$(".canvas-editor").each((i, e) => {
|
||||
var data = $(e).data();
|
||||
var editor = new LiveCodeEditor(e, {
|
||||
runtime: "python-canvas",
|
||||
base_url: "{{ livecode_url }}",
|
||||
codemirror: true,
|
||||
userdata: data,
|
||||
autosave: function(editor, code) {
|
||||
// can't autosave when user is Guest
|
||||
if (frappe.session.user == "Guest") {
|
||||
return;
|
||||
}
|
||||
var data = editor.options.userdata;
|
||||
var code = editor.codemirror.doc.getValue();
|
||||
// console.log("autosaving...")
|
||||
frappe.call("community.lms.api.autosave_section", {
|
||||
section: data.section,
|
||||
code: code
|
||||
}).then((r) => {
|
||||
// TODO: verify
|
||||
})
|
||||
}
|
||||
})
|
||||
editorLookup[data.section] = editor;
|
||||
})
|
||||
|
||||
$(".canvas-editor .reset").each((i, e) => {
|
||||
$(e).on("click", function(event) {
|
||||
var data = $(this).parents(".canvas-editor").data();
|
||||
var section = data.section;
|
||||
frappe.call("community.lms.api.get_section", {
|
||||
name: section
|
||||
}).then(r => {
|
||||
var editor = editorLookup[data.section];
|
||||
editor.codemirror.doc.setValue(r.message.contents);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
</script> -->
|
||||
{%- endblock %}
|
||||
|
||||
@@ -6,6 +6,8 @@ def get_context(context):
|
||||
|
||||
course_name = frappe.form_dict["course"]
|
||||
batch_name = frappe.form_dict["batch"]
|
||||
chapter_index = frappe.form_dict.get("chapter")
|
||||
lesson_index = frappe.form_dict.get("lesson")
|
||||
|
||||
course = Course.find(course_name)
|
||||
if not course:
|
||||
@@ -17,5 +19,16 @@ def get_context(context):
|
||||
frappe.local.flags.redirect_location = "/courses/" + course_name
|
||||
raise frappe.Redirect
|
||||
|
||||
if not chapter_index or not lesson_index:
|
||||
frappe.local.flags.redirect_location = f"/courses/{course_name}/{batch_name}/learn/1.1"
|
||||
raise frappe.Redirect
|
||||
|
||||
context.course = course
|
||||
context.batch = batch
|
||||
context.lesson = course.get_lesson(chapter_index, lesson_index)
|
||||
context.lesson_index = lesson_index
|
||||
context.chapter_index = chapter_index
|
||||
context.livecode_url = get_livecode_url()
|
||||
|
||||
def get_livecode_url():
|
||||
return frappe.db.get_single_value("LMS Settings", "livecode_url")
|
||||
|
||||
@@ -24,29 +24,36 @@
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro LiveCodeEditor(name, code) %}
|
||||
<div class="livecode-editor canvas-editor" id="editor-{{name}}"
|
||||
data-section="{{name}}">
|
||||
{% macro LiveCodeEditor(name, code, is_exercise, last_submitted) %}
|
||||
<div class="livecode-editor livecode-editor-inline" id="editor-{{name}}">
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<div>
|
||||
<textarea class="code">{{code}}</textarea>
|
||||
<div class="livecode-controls">
|
||||
<button type="button" class="run">Run</button>
|
||||
<a href="javascript:;" class="reset">Reset</a>
|
||||
<a href="javascript:;" class="clear">Clear</a>
|
||||
<div class="col-lg-8 col-md-6">
|
||||
<div class="controls">
|
||||
<button class="run">Run</button>
|
||||
<button class="reset">Reset</button>
|
||||
{% if is_exercise %}
|
||||
<button class="submit pull-right btn-primary">Submit</button>
|
||||
{% if last_submitted %}
|
||||
<span class="pull-right" style="padding-right: 10px;">Last submitted {{last_submitted}}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="canvas-wrapper">
|
||||
<canvas class="canvas" width="150" height="150"></canvas>
|
||||
<pre class="output"></pre>
|
||||
</div>
|
||||
<div class="code-editor">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-md-6">
|
||||
<div class="code-wrapper">
|
||||
<textarea class="code">{{code}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6 canvas-wrapper">
|
||||
<canvas width="300" height="300"></canvas>
|
||||
<pre class="output"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user