Skip to content

Commit

Permalink
feat: misc. fixes and enhancements
Browse files Browse the repository at this point in the history
- Now supporting relative links in PDF documents
- Improved logging of browser-related errors
- Introduced error handling when invoking the `MkDocsExporter.render` function in the browser
- Updated documentation plugins
- Improved documentation
  • Loading branch information
adrienbrignon committed Dec 2, 2023
1 parent 741aa1d commit 5100c61
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 43 deletions.
10 changes: 10 additions & 0 deletions macros/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import mkdocs_exporter
import importlib.metadata


def define_env(env):
"""
A hook for the MkDocs Macros plugin.
"""

env.variables['version'] = importlib.metadata.version(mkdocs_exporter.__name__)
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ plugins:
- awesome-pages
- macros:
include_dir: .
modules:
- macros
- git-revision-date-localized:
enable_creation_date: false
- redirects:
Expand Down
30 changes: 23 additions & 7 deletions mkdocs_exporter/plugins/pdf/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import asyncio

from tempfile import NamedTemporaryFile
from mkdocs_exporter.logging import logger
from playwright.async_api import async_playwright

from mkdocs_exporter.logging import logger


class Browser:
"""A web browser instance."""
Expand Down Expand Up @@ -35,6 +36,12 @@ def __init__(self, options: dict = {}):
self.debug = options.get('debug', False)
self.headless = options.get('headless', True)
self.timeout = options.get('timeout', 60_000)
self.levels = {
'warn': 'warning',
'error': 'error',
'info': 'info',
'debug': 'debug'
}


async def launch(self) -> Browser:
Expand All @@ -53,12 +60,7 @@ async def launch(self) -> Browser:
self.browser = await self.playwright.chromium.launch(headless=self.headless, args=self.args)
self.context = await self.browser.new_context()

if self.debug:
async def log(msg):
for arg in msg.args:
logger.info(f"[pdf.browser] ({msg.type}) {await msg.page.title()}\n\t{await arg.json_value()}")

self.context.on('console', log)
self.context.on('console', self.log)

self._launched = True

Expand Down Expand Up @@ -102,3 +104,17 @@ async def print(self, html: str) -> bytes:
await page.close()

return pdf


async def log(self, msg):
"""Logs a message coming from the browser."""

prefix = '[mkdocs-exporter]'
text = msg.text
level = self.levels.get(msg.type, 'info')

if text.startswith(prefix):
text = msg.text[len(prefix):].strip()

if self.debug or level == 'error':
getattr(logger, level)(f"[mkdocs-exporter.pdf.browser] ({msg.type}) {await msg.page.title()}\n{text}")
3 changes: 3 additions & 0 deletions mkdocs_exporter/plugins/pdf/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ class Config(BaseConfig):

browser = c.SubConfig(BrowserConfig)
"""The browser's configuration."""

url = c.Optional(c.Type(str))
"""The base URL that'll be prefixed to links with a relative path."""
8 changes: 6 additions & 2 deletions mkdocs_exporter/plugins/pdf/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import asyncio
import nest_asyncio

from typing import Optional, Coroutine, Sequence

from mkdocs.plugins import BasePlugin
from mkdocs_exporter.page import Page
from mkdocs.plugins import event_priority
from mkdocs_exporter.logging import logger
from mkdocs.livereload import LiveReloadServer
from typing import Optional, Coroutine, Sequence
from mkdocs_exporter.plugins.pdf.config import Config
from mkdocs_exporter.plugins.pdf.renderer import Renderer

Expand Down Expand Up @@ -38,6 +39,9 @@ def on_config(self, config: dict) -> None:

self.watch = []

if self.config.get('url') is None:
self.config['url'] = config['site_url']


def on_serve(self, server: LiveReloadServer, **kwargs) -> LiveReloadServer:
"""Invoked when the website is being served."""
Expand Down Expand Up @@ -82,7 +86,7 @@ def on_pre_build(self, **kwargs) -> None:
if not self._enabled():
return

self.renderer = Renderer(browser_options=self.config.browser)
self.renderer = Renderer(options=self.config)

for stylesheet in self.config.stylesheets:
self.renderer.add_stylesheet(stylesheet)
Expand Down
25 changes: 25 additions & 0 deletions mkdocs_exporter/plugins/pdf/preprocessor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from __future__ import annotations

from urllib.parse import urlparse, urljoin
from mkdocs_exporter.preprocessor import Preprocessor as BasePreprocessor


class Preprocessor(BasePreprocessor):
"""The HTML preprocessor for PDF documents."""


def rewrite_links(self, base: str, root: str) -> None:
"""Rewrite links based on the documentation's URL."""

for element in self.html.find_all('a', href=True):
url = urlparse(element['href'])

if bool(url.netloc):
continue
if not url.path:
continue

final = urlparse(root)
path = urljoin(base, url.path)

element['href'] = url._replace(netloc=final.netloc, scheme=final.scheme, path=path).geturl()
12 changes: 9 additions & 3 deletions mkdocs_exporter/plugins/pdf/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,25 @@
import importlib_resources

from urllib.parse import unquote

from mkdocs_exporter.page import Page
from mkdocs_exporter.resources import js
from mkdocs_exporter.preprocessor import Preprocessor
from mkdocs_exporter.plugins.pdf.browser import Browser
from mkdocs_exporter.renderer import Renderer as BaseRenderer
from mkdocs_exporter.plugins.pdf.preprocessor import Preprocessor


class Renderer(BaseRenderer):
"""The renderer."""

def __init__(self, browser: Browser = None, browser_options: dict = None):

def __init__(self, browser: Browser = None, options: dict = None):
"""The constructor."""

self.options: dict = options
self.scripts: list[str] = []
self.stylesheets: list[str] = []
self.browser = browser or Browser(browser_options)
self.browser = browser or Browser(self.options.get('browser', None))


def add_stylesheet(self, path: str) -> Renderer:
Expand Down Expand Up @@ -69,6 +72,9 @@ def preprocess(self, page: Page) -> str:
preprocessor.teleport()
preprocessor.update_links(base, root)

if self.options.get('url'):
preprocessor.rewrite_links(page.abs_url, self.options['url'])

return preprocessor.done()


Expand Down
1 change: 1 addition & 0 deletions mkdocs_exporter/preprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Union
from urllib.parse import urlparse
from bs4 import BeautifulSoup, Tag

from mkdocs_exporter.theme import Theme
from mkdocs_exporter.logging import logger

Expand Down
6 changes: 5 additions & 1 deletion mkdocs_exporter/resources/js/pdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ window.PagedConfig = {
before: async () => {
if (window.MkDocsExporter) {
if (typeof window.MkDocsExporter.render === 'function') {
await window.MkDocsExporter.render(this);
try {
await window.MkDocsExporter.render(this);
} catch (error) {
console.error('[mkdocs-exporter] Failed to invoke render function', error);
}
}
}
},
Expand Down
12 changes: 6 additions & 6 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "mkdocs-exporter"
version = "5.0.0"
version = "5.1.0"
repository = "https://github.com/adrienbrignon/mkdocs-exporter"
keywords = ["mkdocs", "pdf", "exporter"]
description = "A highly-configurable plugin for MkDocs that exports your pages to PDF files."
Expand Down Expand Up @@ -44,7 +44,7 @@ mkdocs-material = "^9.1.11"
mkdocs-git-revision-date-localized-plugin = "^1.2.0"
mkdocs-git-authors-plugin = "^0.7.0"
mkdocs-awesome-pages-plugin = "^2.9.1"
mkdocs-macros-plugin = "^0.7.0"
mkdocs-macros-plugin = "^1.0.4"
mkdocs-minify-plugin = "^0.6.4"
mkdocs-redirects = "^1.2.0"
mdx-truly-sane-lists = "^1.3"
73 changes: 51 additions & 22 deletions resources/templates/covers/front.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,52 @@
page-break-after: always;
border: 1px solid #fff;
position: relative;
}
.front-cover img {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
image-rendering: optimizeQuality;
}
img {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
image-rendering: optimizeQuality;
}
.front-cover section {
color: #fff;
padding: 0.635cm;
max-width: 10.25cm;
word-wrap: break-word;
margin-top: calc(var(--height) / 2 - var(--offset) - 2cm);
font-size: 13pt;
}
.logo {
position: absolute;
top: calc(2cm);
fill: white;
left: 50%;
transform: translateX(-50%);
.front-cover section > .title {
font-size: 26pt;
font-weight: 500;
line-height: 1.1;
color: #fff;
string-set: title content(text);
> div {
width: 3cm;
text-align: center;
height: 3cm;
}
}
section {
color: #fff;
padding: 0.635cm;
max-width: 10.25cm;
word-wrap: break-word;
margin-top: calc(var(--height) / 2 - var(--offset) - 2cm);
font-size: 13pt;
> .title {
font-size: 32pt;
font-weight: 500;
line-height: 1.1;
margin-top: 1em;
color: #fff;
string-set: title content(text);
}
> .version {
line-height: 1;
font-size: 10pt;
font-family: monospace;
}
}
}
@page {
Expand Down Expand Up @@ -61,8 +82,16 @@
</style>
<div class="front-cover">
<img src="/assets/images/background.png">
<div class="logo">
<div>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="m23 19-3-3v2h-4v2h4v2l3-3m-10 0c0-.3 0-.7.1-1H6v-2h7.8c.5-.8 1.1-1.5 1.9-2H6v-2h12v1.1c.3-.1.7-.1 1-.1s.7 0 1 .1V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h7.8c-.5-.9-.8-1.9-.8-3m0-15.5L18.5 9H13V3.5Z"></path>
</svg>
</div>
</div>
<section>
<div class="brand">{{ config.site_name }}</div>
<div class="version">{{ version }}</div>
<div class="title">{{ page.title }}</div>
</section>
</div>

0 comments on commit 5100c61

Please sign in to comment.