diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py
index fcc1329..72f929a 100644
--- a/renderer/fifty_ohm_html_renderer.py
+++ b/renderer/fifty_ohm_html_renderer.py
@@ -1,5 +1,7 @@
+from itertools import chain
+
from jinja2 import Environment, FileSystemLoader
from mistletoe import Document, HtmlRenderer
@@ -28,8 +30,9 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
section_url = "section.html"
ref_id = 0
- def __init__(self, question_renderer=None, picture_handler=None, photo_handler=None):
- super().__init__(
+ def __init__(self, *extras, question_renderer=None, picture_handler=None, photo_handler=None):
+
+ final_extras = chain(extras,(
Dash,
BlockComment,
Quote,
@@ -46,7 +49,10 @@ class FiftyOhmHtmlRenderer(HtmlRenderer):
Photo,
Table,
Qso,
- )
+ ))
+
+ super().__init__(*final_extras)
+
self.question_renderer = question_renderer
self.picture_handler = picture_handler
self.photo_handler = photo_handler
diff --git a/renderer/fifty_ohm_html_slide_renderer.py b/renderer/fifty_ohm_html_slide_renderer.py
new file mode 100644
index 0000000..54aeb4e
--- /dev/null
+++ b/renderer/fifty_ohm_html_slide_renderer.py
@@ -0,0 +1,35 @@
+from mistletoe import Document
+
+from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer
+
+from .slide_break import SlideBreak
+
+
+class FiftyOhmHtmlSlideRenderer(FiftyOhmHtmlRenderer):
+
+ def __init__(self, question_renderer=None, picture_handler=None, photo_handler=None):
+ super().__init__(
+ SlideBreak,
+ question_renderer=question_renderer,
+ picture_handler=picture_handler,
+ photo_handler=photo_handler,
+ )
+
+ def render_wrapper(self, content):
+ content = "---\n" + content
+ return super().render(Document(content))
+
+ def render_slide_break(self, token):
+ inner = self.render_inner(token)
+
+ if token.attribute is None:
+ return f'\n'
+ if token.attribute == "attention":
+ return f'\n'
+ elif token.attribute == "danger":
+ return f'\n'
+ elif token.attribute == "unit":
+ return f'\n'
+ else:
+ return f'\n'
+
diff --git a/renderer/slide_break.py b/renderer/slide_break.py
new file mode 100644
index 0000000..dadfe08
--- /dev/null
+++ b/renderer/slide_break.py
@@ -0,0 +1,35 @@
+
+# ^\s*---\s*(.*)\s*$
+import re
+
+from mistletoe.block_token import BlockToken, tokenize
+
+
+class SlideBreak(BlockToken):
+ @staticmethod
+ def start(line):
+ return re.match(r"^\s*---.*$", line)
+
+ @classmethod
+ def read(cls, lines):
+ child_lines = []
+ first_line = next(lines) # Consume the line that started the slide break
+
+ match = re.match(r"^\s*---\s*(.*)\s*.*$", first_line)
+ attribute = match.group(1) if match.group(1) else None
+
+ # We have to work with peak here, since a normal for loop would already
+ # consume the next line, which might be a `---` line that marks the
+ # beginning of a new slide as well
+ next_line = lines.peek()
+ while next_line is not None:
+ if re.match(r"^\s*---.*$", next_line) :
+ break
+ else:
+ child_lines.append(next(lines))
+ next_line = lines.peek()
+
+ return tokenize(child_lines), attribute
+
+ def __init__(self, match):
+ self.children, self.attribute = match
diff --git a/src/build.py b/src/build.py
index f5aa932..e726b13 100644
--- a/src/build.py
+++ b/src/build.py
@@ -135,7 +135,11 @@ class Build:
next_chapter_template = self.env.get_template("next_chapter.html")
with open(f'build/{edition}_{section["ident"]}.html', 'w') as file:
- with FiftyOhmHtmlRenderer(self.__build_question, self.__picture_handler, self.__photo_handler) as renderer:
+ with FiftyOhmHtmlRenderer(
+ question_renderer=self.__build_question,
+ picture_handler=self.__picture_handler,
+ photo_handler=self.__photo_handler
+ ) as renderer:
section["content"] = renderer.render(Document(section["content"]))
result = section_template.render(
diff --git a/templates/slide/question.html b/templates/slide/question.html
new file mode 100644
index 0000000..78e782b
--- /dev/null
+++ b/templates/slide/question.html
@@ -0,0 +1,24 @@
+{% set answer_label = ["A", "B", "C", "D"] -%}
+{% if picture_question or (answer_pictures[0] and layout in ["1", "9", None]) -%}
+{# OHM-13: Fix layout for 4x times picture in row to 2x2 field #}
+
+{% else -%}
+
+{% endif -%}
+
{{ number }}: {{ question }}
+ {% if picture_question -%}
+
+ {% endif -%}
+
+ {% if answers[0] -%}
+ {% for answer in answers|shuffle_answers -%}
+
{{ answer_label[loop.index - 1] }}: {{ answer.content }}
+ {% endfor -%}
+ {% endif -%}
+ {% if answer_pictures[0] -%}
+ {% for answer in answer_pictures|shuffle_answers -%}
+
{{ answer_label[loop.index - 1] }}:
+ {% endfor -%}
+ {% endif -%}
+
+
diff --git a/test/acceptanceTestSlides.html b/test/acceptanceTestSlides.html
new file mode 100644
index 0000000..cf78af5
--- /dev/null
+++ b/test/acceptanceTestSlides.html
@@ -0,0 +1,129 @@
+
+
+
+
DARC Ausbildungsplattform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Slide mit Picture
+
+
+ Abbildung TODO: testbild
+
+
+
+
+
+Slide mit Photo
+
+
+ Abbildung TODO: Display eines IC9700-Transceivers, hervorgehoben ist das S-Meter, das den aktuellen Empfangspegel anzeigt
+
+
+
+
+
+
+
+
NB201: Welches Bauteil wird durch das Schaltzeichen symbolisiert?
+
+
+
A: Widerstand
+
B: Batterie
+
C: Diode
+
D: Kondensator
+
+
+
+
+
+Slide Tabelle
+
+| Wert |
+Bereich |
+Bedeutung |
+Englisch |
+
+
+| R |
+1 – 5 |
+Lesbarkeit |
+Readability |
+
+
+| S |
+1 – 9 |
+Signalstärke |
+Signal Strength |
+
+
+| T |
+1 – 9 |
+Tonqualität |
+Tone |
+
+Die Bestandteile des RST-Rapports
+
+
+
+Slide Mit Markdown
Das ist ein Text
+- Das ist ein Bullet
+- Das ist noch ein Bullet
+
Hier wird text unterstrichen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/acceptanceTestSlides.md b/test/acceptanceTestSlides.md
new file mode 100644
index 0000000..18290a3
--- /dev/null
+++ b/test/acceptanceTestSlides.md
@@ -0,0 +1,44 @@
+## Slide mit Picture
+
+[picture:123:p_test:testbild]
+
+---
+
+## Slide mit Photo
+
+[photo:123:n_rst_s-meter:Display eines IC9700-Transceivers, hervorgehoben ist das S-Meter, das den aktuellen Empfangspegel anzeigt]
+
+---
+[question:2482]
+---
+
+## Slide Tabelle
+
+| l: Wert | l: Bereich | l: Bedeutung | l: Englisch |
+| R | 1 - 5 | Lesbarkeit | Readability |
+| S | 1 - 9 | Signalstärke | Signal Strength |
+| T | 1 - 9 | Tonqualität | Tone |
+[table:n_rst:Die Bestandteile des RST-Rapports]
+
+---
+
+## Slide Mit Markdown
+
+Das ist ein *Text*
+
+* Das ist ein Bullet
+* Das ist noch ein Bullet
+
+Hier wird
text unterstrichen
+
+--- unit
+
+## Slide Unit
+
+Slide C
+
+--- data-background="#FF00FF"
+
+## Slide PINK
+
+PINK
\ No newline at end of file
diff --git a/test/test_html.py b/test/test_html.py
index 2d3844c..ec20f45 100644
--- a/test/test_html.py
+++ b/test/test_html.py
@@ -74,7 +74,7 @@ def test_html(capsys):
with capsys.disabled():
with open("test/acceptanceTest.md") as file:
content = file.read()
- with FiftyOhmHtmlRenderer(question_stub) as renderer:
+ with FiftyOhmHtmlRenderer(question_renderer=question_stub) as renderer:
output = renderer.render(Document(content))
with open("test/acceptanceTest.html", "w") as output_file:
pretty = BeautifulSoup(output, "html.parser").prettify()
diff --git a/test/test_html_slides.py b/test/test_html_slides.py
new file mode 100644
index 0000000..f7a9dbd
--- /dev/null
+++ b/test/test_html_slides.py
@@ -0,0 +1,160 @@
+import json
+import random
+
+from jinja2 import Environment, FileSystemLoader
+
+from renderer.fifty_ohm_html_slide_renderer import FiftyOhmHtmlSlideRenderer
+
+
+def parse_katalog():
+ with open("data/fragenkatalog3b.json") as fragenkatalog_file:
+ fragenkatalog = json.load(fragenkatalog_file)
+
+ questions = {}
+
+ for exampart in fragenkatalog["sections"]:
+ for chapter in exampart["sections"]:
+ if "questions" in chapter:
+ for question in chapter["questions"]:
+ questions[question["number"]] = question
+ if "sections" in chapter:
+ for section in chapter["sections"]:
+ for question in section["questions"]:
+ questions[question["number"]] = question
+
+ return questions
+
+def filter_shuffle_answers(seq):
+ try:
+ answers = []
+ firstrun = True
+ for answer in seq:
+ if firstrun:
+ answers.append({"content": answer, "correct": True})
+ firstrun = False
+ else:
+ answers.append({"content": answer, "correct": False})
+ random.shuffle(answers)
+ return answers
+ except Exception:
+ return seq
+
+
+env = Environment(loader=FileSystemLoader("templates/"))
+env.filters["shuffle_answers"] = filter_shuffle_answers
+question_template = env.get_template("slide/question.html")
+questions = parse_katalog()
+
+
+def question_stub(input):
+ """Combines the original question dataset from BNetzA with our internal metadata"""
+ with open("data/metadata.json") as metadata_file:
+ metadata = json.load(metadata_file)
+ number = metadata[f"{input}"]["number"] # Fragennummer z.B. AB123
+
+ question = questions[number]
+ metadata = metadata[f"{input}"]
+
+ if "answer_a" in question:
+ answers = [question["answer_a"], question["answer_b"], question["answer_c"], question["answer_d"]]
+ else:
+ answers = []
+
+ if metadata["picture_a"] != "":
+ answer_pictures = [
+ metadata["picture_a"],
+ metadata["picture_b"],
+ metadata["picture_c"],
+ metadata["picture_d"],
+ ]
+ else:
+ answer_pictures = []
+
+ if "picture_question" in question:
+ picture_question = metadata["picture_question"]
+ else:
+ picture_question = ""
+
+ return question_template.render(
+ question=question["question"],
+ number=number,
+ layout=metadata["layout"],
+ picture_question=picture_question,
+ answers=answers,
+ answer_pictures=answer_pictures,
+ )
+
+
+def print_head():
+ return """
+
+
+
DARC Ausbildungsplattform
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+ #
+ #
+ #
+
+def print_tail():
+ return """
+
+
+
+
+
+
+
+
+
+ """
+
+def test_html_slides(capsys):
+ with capsys.disabled():
+ with open("test/acceptanceTestSlides.md") as file:
+ content = file.read()
+ with FiftyOhmHtmlSlideRenderer(question_stub) as renderer:
+ output = ""
+ output = print_head()
+ output += renderer.render_wrapper(content)
+ output += print_tail()
+ with open("test/acceptanceTestSlides.html", "w") as output_file:
+ output_file.write(output)
diff --git a/test/test_question.py b/test/test_question.py
index d45d9ca..526677d 100644
--- a/test/test_question.py
+++ b/test/test_question.py
@@ -20,7 +20,7 @@ def test_question_html():
def test_function(input):
return f"{input}"
- with FiftyOhmHtmlRenderer(test_function) as renderer:
+ with FiftyOhmHtmlRenderer(question_renderer=test_function) as renderer:
for assertion in assertions:
assert renderer.render(Document(assertion)) == assertions[assertion]
@@ -38,7 +38,7 @@ def test_question_translation_html():
metadata = json.load(file)
return metadata[f"{input}"].get("number")
- with FiftyOhmHtmlRenderer(test_function) as renderer:
+ with FiftyOhmHtmlRenderer(question_renderer=test_function) as renderer:
for assertion in assertions:
assert renderer.render(Document(assertion)) == assertions[assertion]