feat: show image for the exercise
generate the image from the answer and display it along with description. The image is geneated when the exercise is saved.
This commit is contained in:
@@ -3,8 +3,12 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from ..lms_sketch.livecode import livecode_to_svg
|
||||||
|
|
||||||
class Exercise(Document):
|
class Exercise(Document):
|
||||||
|
def before_save(self):
|
||||||
|
self.image = livecode_to_svg(None, self.answer)
|
||||||
|
|
||||||
def get_user_submission(self):
|
def get_user_submission(self):
|
||||||
"""Returns the latest submission for this user.
|
"""Returns the latest submission for this user.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import websocket
|
|||||||
import json
|
import json
|
||||||
from .svg import SVG
|
from .svg import SVG
|
||||||
import frappe
|
import frappe
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
# Files to pass to livecode server
|
# Files to pass to livecode server
|
||||||
# The same code is part of livecode-canvas.js
|
# The same code is part of livecode-canvas.js
|
||||||
@@ -60,9 +61,21 @@ def clear():
|
|||||||
clear()
|
clear()
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
def get_livecode_url():
|
||||||
|
doc = frappe.get_cached_doc("LMS Settings")
|
||||||
|
return doc.livecode_url
|
||||||
|
|
||||||
|
def get_livecode_ws_url():
|
||||||
|
url = urlparse(get_livecode_url())
|
||||||
|
protocol = "wss" if url.scheme == "https" else "ws"
|
||||||
|
return protocol + "://" + url.netloc + "/livecode"
|
||||||
|
|
||||||
def livecode_to_svg(livecode_ws_url, code, *, timeout=3):
|
def livecode_to_svg(livecode_ws_url, code, *, timeout=3):
|
||||||
"""Renders the code as svg.
|
"""Renders the code as svg.
|
||||||
"""
|
"""
|
||||||
|
if livecode_ws_url is None:
|
||||||
|
livecode_ws_url = get_livecode_ws_url()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ws = websocket.WebSocket()
|
ws = websocket.WebSocket()
|
||||||
ws.settimeout(timeout)
|
ws.settimeout(timeout)
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
<h2>{{ exercise.title }}</h2>
|
<h2>{{ exercise.title }}</h2>
|
||||||
<div class="exercise-description">{{frappe.utils.md_to_html(exercise.description)}}</div>
|
<div class="exercise-description">{{frappe.utils.md_to_html(exercise.description)}}</div>
|
||||||
|
|
||||||
|
{% if exercise.image %}
|
||||||
|
<div class="exercise-image">{{exercise.image}}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% set submission = exercise.get_user_submission() %}
|
{% set submission = exercise.get_user_submission() %}
|
||||||
|
|
||||||
{{ LiveCodeEditor(exercise.name,
|
{{ LiveCodeEditor(exercise.name,
|
||||||
@@ -12,3 +16,12 @@
|
|||||||
is_exercise=True,
|
is_exercise=True,
|
||||||
last_submitted=submission and submission.creation) }}
|
last_submitted=submission and submission.creation) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
.exercise-image svg {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -306,3 +306,14 @@ section.lightgray {
|
|||||||
.lesson-page {
|
.lesson-page {
|
||||||
margin: 20px 0px;
|
margin: 20px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lesson-pagination {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exercise-image svg {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user