Coverage for src/mkdocs_iframe/plugin.py: 86.54%
78 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-06 09:32 -0400
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-06 09:32 -0400
1"""This module contains the `mkdocs_iframe` plugin."""
3from __future__ import annotations
5import re
6import shutil
7import textwrap
8from pathlib import Path
9from tempfile import mkdtemp
10from typing import TYPE_CHECKING, Any, Sequence
12from mkdocs.config.config_options import Type as MkType
13from mkdocs.plugins import BasePlugin
14from mkdocs.structure.files import File, Files
16from mkdocs_iframe.loggers import get_logger
18if TYPE_CHECKING:
19 from mkdocs.config import Config
21log = get_logger(__name__)
24class Report:
25 """HTML Report."""
27 def __init__(
28 self,
29 *,
30 name: str,
31 path: str | None = None,
32 root: str = "index.html",
33 page: str | None = None,
34 use_directory_urls: bool = False,
35 ):
36 """Initialize Report."""
37 self.name = name
38 self.path = path or f"html{name}"
39 self.root = root
40 self.page = page or f"{name}.md"
41 self.id = f"{name}iframe"
42 self.use_directory_urls = use_directory_urls
44 def root_file(self) -> str:
45 """Return the root page of the report."""
46 report_index = self.root
47 if report_index == "index.html": 47 ↛ 50line 47 didn't jump to line 50, because the condition on line 47 was never false
48 report_index = f"{self.name}index.html"
50 if self.use_directory_urls: 50 ↛ 52line 50 didn't jump to line 52, because the condition on line 50 was never false
51 return report_index
52 return f"{self.name}/{report_index}"
54 def nav_page(self) -> str:
55 """Generate the NAV page source."""
56 root = self.root_file()
58 style = textwrap.dedent(
59 """
60 <style>
61 article h1, article > a, .md-sidebar--secondary {
62 display: none !important;
63 }
64 </style>
65 """,
66 )
68 iframe = textwrap.dedent(
69 f"""
70 <iframe
71 id="{self.id}"
72 src="{root}"
73 frameborder="0"
74 scrolling="no"
75 onload="resizeIframe();"
76 width="100%">
77 </iframe>
78 """,
79 )
81 script = textwrap.dedent(
82 f"""
83 <script>
84 var {self.id} = document.getElementById("{self.id}");
86 function resizeIframe() {{
87 {self.id}.style.height = {self.id}.contentWindow.document.documentElement.offsetHeight + 'px';
88 }}
90 testiframe.contentWindow.document.body.onclick = function() {{
91 {self.id}.contentWindow.location.reload();
92 }}
93 </script>
95 """,
96 )
97 return style + iframe + script
100class MkDocsIframePlugin(BasePlugin):
101 """The MkDocs plugin to integrate the HTML reports in the site."""
103 config_scheme: Sequence[tuple[str, MkType]] = (("reports", MkType(list, default=[])),)
105 def reports(self, *, use_directory_urls: bool = False) -> list[Report]:
106 """Convert config data to Reports."""
107 res = []
108 for report in self.config["reports"]:
109 if isinstance(report, str): 109 ↛ 110line 109 didn't jump to line 110, because the condition on line 109 was never true
110 res.append(Report(use_directory_urls=use_directory_urls, name=report))
111 else:
112 res.append(Report(use_directory_urls=use_directory_urls, **report))
113 return res
115 def on_files(self, files: Files, config: Config, **kwargs: Any) -> Files: # noqa: ARG002
116 """Add the html report to the navigation.
118 Hook for the [`on_files` event](https://www.mkdocs.org/user-guide/plugins/#on_files).
120 Arguments:
121 files: The files collection.
122 config: The MkDocs config object.
123 **kwargs: Additional arguments passed by MkDocs.
125 Returns:
126 The modified files collection.
128 """
129 site_dir = Path(config["site_dir"])
130 use_directory_urls = config["use_directory_urls"]
131 for report in self.reports(use_directory_urls=use_directory_urls):
132 page_contents = report.nav_page()
133 tmp_dir = mkdtemp()
134 tmp_file = Path(tmp_dir) / report.page
135 with tmp_file.open("w") as fp:
136 fp.write(page_contents)
138 files.append(
139 File(
140 report.page,
141 str(tmp_file.parent),
142 str(site_dir),
143 use_directory_urls,
144 ),
145 )
147 return files
149 def on_post_build(self, config: Config, **kwargs: Any) -> None: # noqa: ARG002
150 """Copy the HTML reports into the site directory.
152 Hook for the [`on_post_build` event](https://www.mkdocs.org/user-guide/plugins/#on_post_build).
154 Arguments:
155 config: The MkDocs config object.
156 **kwargs: Additional arguments passed by MkDocs.
158 """
159 site_dir = Path(config["site_dir"])
160 use_directory_urls = config["use_directory_urls"]
162 for report in self.reports(use_directory_urls=use_directory_urls):
163 report_dir = site_dir / report.name
164 tmp_index = site_dir / f".{report.name}-tmp.html"
166 if report.root == "index.html": 166 ↛ 172line 166 didn't jump to line 172, because the condition on line 166 was never false
167 if config["use_directory_urls"]: 167 ↛ 170line 167 didn't jump to line 170, because the condition on line 167 was never false
168 shutil.move(str(report_dir / "index.html"), tmp_index)
169 else:
170 shutil.move(str(report_dir.with_suffix(".html")), tmp_index)
172 shutil.rmtree(str(report_dir), ignore_errors=True)
173 try:
174 shutil.copytree(report.path, str(report_dir))
175 except FileNotFoundError:
176 log.warning(f"No such HTML report directory: {report.path}")
177 return
179 if report.root == "index.html": 179 ↛ 162line 179 didn't jump to line 162, because the condition on line 179 was never false
180 report_root = report.root_file()
182 shutil.move(str(report_dir / "index.html"), report_dir / report_root)
183 if use_directory_urls: 183 ↛ 186line 183 didn't jump to line 186, because the condition on line 183 was never false
184 shutil.move(str(tmp_index), report_dir / "index.html")
185 else:
186 shutil.move(str(tmp_index), report_dir.with_suffix(".html"))
188 for html_file in report_dir.iterdir():
189 if html_file.suffix == ".html" and html_file.name != "index.html":
190 html_file.write_text(
191 re.sub(r'href="index\.html"', f'href="{report_root}"', html_file.read_text()),
192 )