diff --git a/build.py b/build.py index 3e8b1db..f86c6e7 100644 --- a/build.py +++ b/build.py @@ -16,6 +16,7 @@ dl.download_edition("N") dl.download_question_metadata() dl.download_pictures() dl.download_photos() +dl.download_includes() dl.download_snippets() dl.download_content() diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index fcc1329..e0d73b7 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -6,6 +6,7 @@ from mistletoe import Document, HtmlRenderer from .comment import BlockComment from .dash import Dash from .halfwidth_spaces import HalfwidthSpaces +from .include import Include from .morse import Morse from .nonbreaking_spaces import NonbreakingSpaces, NonbreakingSpacesDots from .photo import Photo @@ -28,7 +29,13 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): section_url = "section.html" ref_id = 0 - def __init__(self, question_renderer=None, picture_handler=None, photo_handler=None): + def __init__( + self, + question_renderer=None, + picture_handler=None, + photo_handler=None, + include_handler=None + ) : super().__init__( Dash, BlockComment, @@ -46,10 +53,12 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): Photo, Table, Qso, + Include ) self.question_renderer = question_renderer self.picture_handler = picture_handler self.photo_handler = photo_handler + self.include_handler = include_handler def render_dash(self, token): return " – " @@ -227,3 +236,6 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): table += "" return table + + def render_include(self, token): + return self.include_handler(token.ident) diff --git a/renderer/include.py b/renderer/include.py new file mode 100644 index 0000000..9f2a690 --- /dev/null +++ b/renderer/include.py @@ -0,0 +1,24 @@ +import re + +from mistletoe.block_token import BlockToken + + +class Include(BlockToken): + """ + Block token ("[include:ident]"). + Includes raw html or javascript code from a file with the given identifier. + """ + + @staticmethod + def start(line): + return re.match(r"^\s*\[include:\s*[^\]]+\]", line) + + @classmethod + def read(cls, lines): + re.compile(r'') + line = next(lines) # Consume the line with the include directive + ident = re.match(r"^\s*\[include:\s*([^\]]+)\]", line).group(1) + return ident + + def __init__(self, match): + self.ident = match \ No newline at end of file diff --git a/src/build.py b/src/build.py index 65e05b0..a4990ca 100644 --- a/src/build.py +++ b/src/build.py @@ -130,6 +130,11 @@ class Build: result = self.__build_page(result, course_wrapper=True) file.write(result) + def __include_handler(self, include): + with open("data/includes.json") as file: + includes = json.load(file) + return includes.get(include) + # cached def __build_section(self, edition, edition_name, section, chapter, next_section=None, next_chapter=None): section_template = self.env.get_template("section.html") @@ -137,7 +142,12 @@ 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( + self.__build_question, + self.__picture_handler, + self.__photo_handler, + self.__include_handler + ) as renderer: section["content"] = renderer.render(Document(section["content"])) result = section_template.render( diff --git a/src/download.py b/src/download.py index 0488f11..9295825 100644 --- a/src/download.py +++ b/src/download.py @@ -133,6 +133,16 @@ class Download: delayed(build_picture)(picture) for picture in tqdm(pictures, desc="Build All Pictures") ) + def download_includes(self): + includes = self.api.get("items/include", params={"limit": -1}) + + result = {} + for include in tqdm(includes, desc="Downloading includes"): + result[include["ident"]] = include["content"] + + with open("data/includes.json", "w") as f: + json.dump(result, f, indent=4) + def download_snippets(self): snippets = {} for snippet in tqdm(self.content_api.get("items/snippet"), desc="Downloading snippets"): @@ -152,4 +162,4 @@ class Download: ) with open("data/content.json", "w", encoding="utf-8") as file: - json.dump(contents, file, ensure_ascii=False, indent=4) \ No newline at end of file + json.dump(contents, file, ensure_ascii=False, indent=4) diff --git a/test/acceptanceTest.md b/test/acceptanceTest.md index 97e5bcd..0fb2698 100644 --- a/test/acceptanceTest.md +++ b/test/acceptanceTest.md @@ -1,5 +1,7 @@ % Kommentar: DARC-DOWN-TEST +[include:test] + Das ist eine Item-Liste: * Erster Eintrag diff --git a/test/test_html.py b/test/test_html.py index 2d3844c..05b8964 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -69,12 +69,19 @@ def question_stub(input): answer_pictures=answer_pictures, ) +def include_stub(include): + with open("data/includes.json") as file: + includes = json.load(file) + return includes.get(include) 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, + include_handler=include_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_include.py b/test/test_include.py new file mode 100644 index 0000000..24c02f7 --- /dev/null +++ b/test/test_include.py @@ -0,0 +1,18 @@ +import pytest +from mistletoe import Document + +from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer + + +@pytest.mark.html +def test_include_html(): + assertions = { + '[include:ident]': "ident\n", + } + + def test_function(input): + return f"{input}" + + with FiftyOhmHtmlRenderer(include_handler=test_function) as renderer: + for assertion in assertions: + assert renderer.render(Document(assertion)) == assertions[assertion] \ No newline at end of file