Merge branch 'main' of https://github.com/frappe/community into main
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/livecode.html" import LiveCodeEditor with context %}
|
||||
{% block title %}{{topic.title}} ({{course.title}}){% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Topic {{topic.title}} of the course {{course.title}}" />
|
||||
@@ -7,6 +8,7 @@
|
||||
</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>
|
||||
@@ -42,7 +44,7 @@
|
||||
{% if s.type == "text" %}
|
||||
{{ render_section_text(s) }}
|
||||
{% elif s.type == "code" %}
|
||||
{{ render_section_code(s) }}
|
||||
{{ LiveCodeEditor(s.name, s.code) }}
|
||||
{% else %}
|
||||
<div>Unknown section type: {{s.type}}</div>
|
||||
{% endif %}
|
||||
@@ -52,28 +54,6 @@
|
||||
{{ s.contents | markdown }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_section_code(s) %}
|
||||
<div class="canvas-editor row no-gutters" id="editor-{{s.name}}">
|
||||
<div class="col-sm">
|
||||
<div class="heading">
|
||||
<button class="run">Run</button>
|
||||
<h2>Editor</h2>
|
||||
</div>
|
||||
<textarea class="code">{{s.code}}</textarea>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="heading">
|
||||
<h2>Output</h2>
|
||||
</div>
|
||||
<div class="canvas-wrapper">
|
||||
<canvas class="canvas" width="300" height="300">Dashed box</canvas>
|
||||
<pre class="output"></pre>
|
||||
</div>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{%- block script %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript" src="{{ livecode_url }}/static/livecode.js"></script>
|
||||
@@ -89,73 +69,3 @@
|
||||
})
|
||||
</script>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block style %}
|
||||
{{ super() }}
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
.canvas-wrapper {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.canvas-editor canvas {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
border: 1px solid #ddd;
|
||||
height: 300px;
|
||||
width: 300px;
|
||||
}
|
||||
.canvas-wrapper .output {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
background-color: rgba(255, 255, 255, 0);
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.canvas-editor .code {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
min-height: 330px;
|
||||
resize: none;
|
||||
}
|
||||
.canvas-editor .output {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
background: #eee;
|
||||
padding: 10px;
|
||||
clear: both;
|
||||
color: #212529;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.canvas-editor h2 {
|
||||
font-size: 1.2em;
|
||||
text-transform: uppercase;
|
||||
margin: 0px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.canvas-editor .run {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.canvas-editor .col-sm {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* .canvas-editor canvas {
|
||||
float: left;
|
||||
border: 1px solid #ddd;
|
||||
padding: 5px;
|
||||
margin: 10px;
|
||||
} */
|
||||
|
||||
</style>
|
||||
{%- endblock %}
|
||||
|
||||
40
community/www/macros/livecode.html
Normal file
40
community/www/macros/livecode.html
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
{% macro LiveCodeEditor(name, code) %}
|
||||
<div class="canvas-editor row no-gutters" id="editor-{{name}}">
|
||||
<div class="col-sm">
|
||||
<div class="heading">
|
||||
<button class="run">Run</button>
|
||||
<h2>Editor</h2>
|
||||
</div>
|
||||
<textarea class="code">{{code}}</textarea>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="heading">
|
||||
<h2>Output</h2>
|
||||
</div>
|
||||
<div class="canvas-wrapper">
|
||||
<canvas class="canvas" width="300" height="300"></canvas>
|
||||
<pre class="output"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro LiveCodeEditorJS(name, code) %}
|
||||
<script type="text/javascript" src="{{ livecode_url }}/static/livecode.js"></script>
|
||||
<script type="text/javascript">
|
||||
var livecodeEditors = [];
|
||||
|
||||
$(function() {
|
||||
$(".canvas-editor").each((i, e) => {
|
||||
var editor = new LiveCodeEditor(e, {
|
||||
runtime: "python-canvas",
|
||||
base_url: "{{ livecode_url }}",
|
||||
codemirror: true
|
||||
})
|
||||
livecodeEditors.push(editor);
|
||||
})
|
||||
})
|
||||
</script>
|
||||
{% endmacro %}
|
||||
47
community/www/sketches/index.html
Normal file
47
community/www/sketches/index.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/livecode.html" import LiveCodeEditor, LiveCodeEditorJS %}
|
||||
|
||||
{% block title %}Sketches{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Sketches" />
|
||||
<meta name="keywords" content="sketches" />
|
||||
<link rel="stylesheet" href="/assets/css/lms.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="top-section" style="padding: 1rem 0rem;">
|
||||
<div class='container pb-5'>
|
||||
<h1>Recent Sketches</h1>
|
||||
|
||||
<a href="/sketches/sketch?sketch=new">Create a New Sketch</a>
|
||||
</div>
|
||||
<div class='container'>
|
||||
<div class="row row-cols-1 row-cols-xl-5 row-cols-lg-4 row-cols-md-3 row-cols-sm-2 ">
|
||||
{% for sketch in sketches %}
|
||||
<div class="col mb-4">
|
||||
<div class="card" style="width: 200px;">
|
||||
<div class="card-img-top">
|
||||
<a href="/sketches/sketch?sketch={{sketch.name}}">
|
||||
{{ sketch.to_svg() }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
By {{sketch.get_owner_name()}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
{{super()}}
|
||||
<style type="text/css">
|
||||
svg {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
7
community/www/sketches/index.py
Normal file
7
community/www/sketches/index.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import frappe
|
||||
from ...lms.doctype.lms_sketch.lms_sketch import get_recent_sketches
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.sketches = get_recent_sketches()
|
||||
|
||||
109
community/www/sketches/sketch.html
Normal file
109
community/www/sketches/sketch.html
Normal file
@@ -0,0 +1,109 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/livecode.html" import LiveCodeEditor, LiveCodeEditorJS with context %}
|
||||
|
||||
{% block title %}{{sketch.title}}{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Sketch {{sketch.title}}" />
|
||||
<meta name="keywords" content="sketch {{sketch.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 %}
|
||||
<section class="top-section" style="padding: 1rem 0rem;">
|
||||
<div class='container pb-5'>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item" aria-current="page"><a href="/sketches">Sketches</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="sketch-header">
|
||||
{% if editable %}
|
||||
<input type="button" class="pull-right" id="sketch-save" value="Save"/>
|
||||
<h1 class="sketch-title">
|
||||
<input type="text" name="title" id="sketch-title" value="{{ sketch.title }}" />
|
||||
</h1>
|
||||
{% else %}
|
||||
<h1 class="sketch-title">{{sketch.title}}</h1>
|
||||
{% endif %}
|
||||
<div class="sketch-owner-wrapper">By <span class="sketch-owner">{{sketch.get_owner_name()}}</span></div>
|
||||
</div>
|
||||
|
||||
{% if sketch.is_new() and not editable %}
|
||||
<div class="alert alert-warning">
|
||||
Please login to save this sketch.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="sketch-editor">
|
||||
{{LiveCodeEditor(sketch.name, sketch.code) }}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{%- block script %}
|
||||
{{ super() }}
|
||||
{{ LiveCodeEditorJS() }}
|
||||
|
||||
<script type="text/javascript">
|
||||
var sketch_name = {{ sketch.name | tojson }};
|
||||
|
||||
function saveSketch() {
|
||||
var title = $("#sketch-title").val()
|
||||
var code = livecodeEditors[0].codemirror.doc.getValue()
|
||||
frappe.call('community.lms.doctype.lms_sketch.lms_sketch.save_sketch', {
|
||||
name: sketch_name,
|
||||
title: title,
|
||||
code: code
|
||||
})
|
||||
.then(r => {
|
||||
var msg = r.message;
|
||||
if (!msg.ok) {
|
||||
var error = msg.error || "Save failed."
|
||||
frappe.msgprint({
|
||||
"title": "Error",
|
||||
"indicator": "red",
|
||||
"message": error
|
||||
});
|
||||
}
|
||||
else if (msg.status == "created") {
|
||||
var path = "/sketches/sketch?sketch=" + msg.name;
|
||||
var url = window.location.protocol + "//" + window.location.host + path
|
||||
window.history.pushState({path: url}, '', url);
|
||||
sketch_name = name;
|
||||
|
||||
frappe.msgprint({
|
||||
"title": "Notification",
|
||||
"indicator": "green",
|
||||
"message": "New sketch has been saved!"
|
||||
});
|
||||
}
|
||||
else if (msg.status == "updated") {
|
||||
frappe.msgprint({
|
||||
"title": "Notification",
|
||||
"indicator": "green",
|
||||
"message": "The sketch has been saved!"
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$("#sketch-save").click(function() {
|
||||
saveSketch();
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{%- endblock %}
|
||||
|
||||
41
community/www/sketches/sketch.py
Normal file
41
community/www/sketches/sketch.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import frappe
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
course_name = get_queryparam("sketch", '/sketches')
|
||||
context.sketch = get_sketch(course_name)
|
||||
context.livecode_url = get_livecode_url()
|
||||
context.editable = is_editable(context.sketch, frappe.session.user)
|
||||
|
||||
def is_editable(sketch, user):
|
||||
if sketch.is_new():
|
||||
# new sketches can be editable by any logged in user
|
||||
return user != "Guest"
|
||||
else:
|
||||
# existing sketches are editable by the owner
|
||||
return sketch.owner == user
|
||||
|
||||
def get_livecode_url():
|
||||
doc = frappe.get_doc("LMS Settings")
|
||||
return doc.livecode_url
|
||||
|
||||
def get_queryparam(name, redirect_when_not_found):
|
||||
try:
|
||||
return frappe.form_dict[name]
|
||||
except KeyError:
|
||||
frappe.local.flags.redirect_location = redirect_when_not_found
|
||||
raise frappe.Redirect
|
||||
|
||||
def get_sketch(name):
|
||||
if name == 'new':
|
||||
sketch = frappe.new_doc('LMS Sketch')
|
||||
sketch.name = "new"
|
||||
sketch.title = "New Sketch"
|
||||
sketch.code = "circle(100, 100, 50)"
|
||||
return sketch
|
||||
|
||||
try:
|
||||
return frappe.get_doc('LMS Sketch', name)
|
||||
except frappe.exceptions.DoesNotExistError:
|
||||
raise frappe.NotFound
|
||||
|
||||
Reference in New Issue
Block a user