Merge branch 'main' of https://github.com/frappe/community into main
This commit is contained in:
@@ -8,7 +8,8 @@
|
|||||||
"type",
|
"type",
|
||||||
"contents",
|
"contents",
|
||||||
"code",
|
"code",
|
||||||
"attrs"
|
"attrs",
|
||||||
|
"index"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -37,12 +38,17 @@
|
|||||||
"fieldname": "attrs",
|
"fieldname": "attrs",
|
||||||
"fieldtype": "Long Text",
|
"fieldtype": "Long Text",
|
||||||
"label": "attrs"
|
"label": "attrs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "index",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Index"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-05 17:12:57.997046",
|
"modified": "2021-03-12 17:56:23.118854",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "LMS Section",
|
"name": "LMS Section",
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ from __future__ import unicode_literals
|
|||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class LMSSection(Document):
|
class LMSSection(Document):
|
||||||
pass
|
def __repr__(self):
|
||||||
|
return f"<LMSSection {self.label!r}>"
|
||||||
|
|||||||
@@ -3,8 +3,22 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
# import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from .section_parser import SectionParser
|
||||||
|
|
||||||
class LMSTopic(Document):
|
class LMSTopic(Document):
|
||||||
pass
|
def before_save(self):
|
||||||
|
sections = SectionParser().parse(self.description)
|
||||||
|
self.sections = [self.make_lms_section(i, s) for i, s in enumerate(sections)]
|
||||||
|
|
||||||
|
def get_sections(self):
|
||||||
|
return sorted(self.sections, key=lambda s: s.index)
|
||||||
|
|
||||||
|
def make_lms_section(self, index, section):
|
||||||
|
s = frappe.new_doc('LMS Section', parent_doc=self, parentfield='sections')
|
||||||
|
s.type = section.type
|
||||||
|
s.label = section.label
|
||||||
|
s.contents = section.contents
|
||||||
|
s.index = index
|
||||||
|
return s
|
||||||
|
|||||||
79
community/lms/doctype/lms_topic/section_parser.py
Normal file
79
community/lms/doctype/lms_topic/section_parser.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"""Utility to split the text in the topic into multiple sections.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import re
|
||||||
|
from typing import List, Tuple, Dict, Iterator
|
||||||
|
|
||||||
|
RE_SECTION = re.compile(r"^\{\{\s(\w+)\s*(?:\((.*)\))?\s*\}\}\s*")
|
||||||
|
class SectionParser:
|
||||||
|
def parse(self, text: str) -> Iterator[Section]:
|
||||||
|
"""Parses given text into sections and return an iterator over sections.
|
||||||
|
"""
|
||||||
|
lines = text.splitlines()
|
||||||
|
marked_lines = self.parse_lines(lines)
|
||||||
|
return self.group_sections(marked_lines)
|
||||||
|
|
||||||
|
def parse_lines(self, lines: List[str]) -> List[Tuple[str, str, str]]:
|
||||||
|
for line in lines:
|
||||||
|
m = RE_SECTION.match(line)
|
||||||
|
if m:
|
||||||
|
yield m.group(1), self.parse_attrs(m.group(2)), None
|
||||||
|
else:
|
||||||
|
yield None, None, line
|
||||||
|
|
||||||
|
def parse_attrs(self, attrs_str: str) -> Dict[str, str]:
|
||||||
|
# XXX-Anand: Hack
|
||||||
|
code = "dict({})".format(attrs_str or "")
|
||||||
|
return eval(code)
|
||||||
|
|
||||||
|
def group_sections(self, marked_lines) -> Iterator[Section]:
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
def make_section(type='text', id=None, label=None, **attrs):
|
||||||
|
nonlocal index
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
id = id or f"section-{index}"
|
||||||
|
label = label or id
|
||||||
|
return Section(
|
||||||
|
type=type,
|
||||||
|
id=id,
|
||||||
|
label=label,
|
||||||
|
attrs=attrs)
|
||||||
|
|
||||||
|
section = make_section("text")
|
||||||
|
|
||||||
|
for mark, attrs, line in marked_lines:
|
||||||
|
if not mark:
|
||||||
|
section.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield section
|
||||||
|
|
||||||
|
if mark == 'end':
|
||||||
|
section = make_section(type='text')
|
||||||
|
else:
|
||||||
|
section = make_section(**attrs)
|
||||||
|
|
||||||
|
yield section
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Section:
|
||||||
|
"""One section of the Topic.
|
||||||
|
"""
|
||||||
|
type: str
|
||||||
|
id: str
|
||||||
|
label: str
|
||||||
|
contents: str = ""
|
||||||
|
attrs: dict = None
|
||||||
|
|
||||||
|
def append(self, line):
|
||||||
|
if not line.endswith("\n"):
|
||||||
|
line = line + "\n"
|
||||||
|
self.contents += line
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
attrs = dict(type=self.type, id=self.id, label=self.label, **self.attrs)
|
||||||
|
attrs_str = ", ".join(f'{k}="{v}"' for k, v in attrs.items())
|
||||||
|
return f'<Section({attrs_str})>'
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<h1>{{ topic.title }}</h1>
|
<h1>{{ topic.title }}</h1>
|
||||||
|
|
||||||
{% for s in topic.sections %}
|
{% for s in topic.get_sections() %}
|
||||||
<div class="section section-{{ s.type }}">
|
<div class="section section-{{ s.type }}">
|
||||||
{{ render_section(s) }}
|
{{ render_section(s) }}
|
||||||
</div>
|
</div>
|
||||||
@@ -43,8 +43,8 @@
|
|||||||
{% macro render_section(s) %}
|
{% macro render_section(s) %}
|
||||||
{% if s.type == "text" %}
|
{% if s.type == "text" %}
|
||||||
{{ render_section_text(s) }}
|
{{ render_section_text(s) }}
|
||||||
{% elif s.type == "code" %}
|
{% elif s.type == "example" or s.type == "code" %}
|
||||||
{{ LiveCodeEditor(s.name, s.code) }}
|
{{ LiveCodeEditor(s.name, s.contents) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div>Unknown section type: {{s.type}}</div>
|
<div>Unknown section type: {{s.type}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user