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 72f929a..c2e9c1e 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -8,6 +8,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 @@ -30,7 +31,14 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): section_url = "section.html" ref_id = 0 - def __init__(self, *extras, question_renderer=None, picture_handler=None, photo_handler=None): + def __init__( + self, + *extras, + question_renderer=None, + picture_handler=None, + photo_handler=None, + include_handler=None + ): final_extras = chain(extras,( Dash, @@ -49,6 +57,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): Photo, Table, Qso, + Include, )) super().__init__(*final_extras) @@ -56,6 +65,7 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): 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 " – " @@ -233,3 +243,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 ea9364a..d915ce9 100644 --- a/src/build.py +++ b/src/build.py @@ -138,6 +138,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, section_id, chapter, next_section=None, next_chapter=None): section_template = self.env.get_template("html/section.html") @@ -148,7 +153,8 @@ class Build: with FiftyOhmHtmlRenderer( question_renderer=self.__build_question, picture_handler=self.__picture_handler, - photo_handler=self.__photo_handler + photo_handler=self.__photo_handler, + include_handler=self.__include_handler ) as renderer: section["content"] = renderer.render(Document(section["content"])) @@ -182,34 +188,8 @@ class Build: with FiftyOhmHtmlSlideRenderer( question_renderer=self.__build_question_slide, picture_handler=self.__picture_handler, - photo_handler=self.__photo_handler - ) as renderer: - result = "
\n" - result += f'
\n

{chapter["title"]}

\n
\n' - result += help_template.render() - result += "
\n" - for section in sections: - tmp = f'
\n

{section["title"]}

\n
\n' - tmp += renderer.render_wrapper(section["slide"]) - result += f"
{tmp}
\n" - result += next_template.render( - edition=edition, - next_chapter=next_chapter, - chapter=chapter, - ) - - result = slide_template.render(content=result) - file.write(result) - - def __build_chapter_slidedeck(self, edition, chapter, sections, next_chapter): - with open(f'build/{edition}_slide_{chapter["ident"]}.html', 'w') as file: - slide_template = self.env.get_template("slide/slide.html") - help_template = self.env.get_template("slide/help.html") - next_template = self.env.get_template("slide/next.html") - with FiftyOhmHtmlSlideRenderer( - question_renderer=self.__build_question_slide, - picture_handler=self.__picture_handler, - photo_handler=self.__photo_handler + photo_handler=self.__photo_handler, + include_handler=self.__include_handler ) as renderer: result = "
\n" result += f'
\n

{chapter["title"]}

\n
\n' @@ -286,7 +266,8 @@ class Build: with FiftyOhmHtmlRenderer( question_renderer=self.__build_question, picture_handler=self.__picture_handler, - photo_handler=self.__photo_handler + photo_handler=self.__photo_handler, + include_handler=self.__include_handler ) as renderer: for key, value in snippets.items(): snippets[key] = renderer.render_inner(Document(value)) 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 ec20f45..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_renderer=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