diff --git a/community/lms/doctype/lms_section/lms_section.json b/community/lms/doctype/lms_section/lms_section.json index 9af77471..4a275d32 100644 --- a/community/lms/doctype/lms_section/lms_section.json +++ b/community/lms/doctype/lms_section/lms_section.json @@ -8,7 +8,8 @@ "type", "contents", "code", - "attrs" + "attrs", + "index" ], "fields": [ { @@ -37,12 +38,17 @@ "fieldname": "attrs", "fieldtype": "Long Text", "label": "attrs" + }, + { + "fieldname": "index", + "fieldtype": "Int", + "label": "Index" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-03-05 17:12:57.997046", + "modified": "2021-03-12 17:56:23.118854", "modified_by": "Administrator", "module": "LMS", "name": "LMS Section", diff --git a/community/lms/doctype/lms_section/lms_section.py b/community/lms/doctype/lms_section/lms_section.py index a0eaa105..ad40ece6 100644 --- a/community/lms/doctype/lms_section/lms_section.py +++ b/community/lms/doctype/lms_section/lms_section.py @@ -7,4 +7,5 @@ from __future__ import unicode_literals from frappe.model.document import Document class LMSSection(Document): - pass + def __repr__(self): + return f"" diff --git a/community/lms/doctype/lms_topic/lms_topic.py b/community/lms/doctype/lms_topic/lms_topic.py index 7521aeb4..acf5fe4e 100644 --- a/community/lms/doctype/lms_topic/lms_topic.py +++ b/community/lms/doctype/lms_topic/lms_topic.py @@ -3,8 +3,22 @@ # For license information, please see license.txt from __future__ import unicode_literals -# import frappe +import frappe from frappe.model.document import Document +from .section_parser import SectionParser 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 diff --git a/community/lms/doctype/lms_topic/section_parser.py b/community/lms/doctype/lms_topic/section_parser.py new file mode 100644 index 00000000..6382d133 --- /dev/null +++ b/community/lms/doctype/lms_topic/section_parser.py @@ -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'' diff --git a/community/www/courses/topic.html b/community/www/courses/topic.html index 0cc30d38..205bbeee 100644 --- a/community/www/courses/topic.html +++ b/community/www/courses/topic.html @@ -30,7 +30,7 @@

{{ topic.title }}

- {% for s in topic.sections %} + {% for s in topic.get_sections() %}
{{ render_section(s) }}
@@ -43,8 +43,8 @@ {% macro render_section(s) %} {% if s.type == "text" %} {{ render_section_text(s) }} - {% elif s.type == "code" %} - {{ LiveCodeEditor(s.name, s.code) }} + {% elif s.type == "example" or s.type == "code" %} + {{ LiveCodeEditor(s.name, s.contents) }} {% else %}
Unknown section type: {{s.type}}
{% endif %}