Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ site
report.css
build
venv
.*.sw[pon]
11 changes: 11 additions & 0 deletions mkpdfs_mkdocs/design/report.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

$bgColor: #2196f3;
$bgTextColor: #fff;
$lightTextColor: #707070;


@font-face {
Expand Down Expand Up @@ -276,6 +277,9 @@ html body article {
break-before: right;
break-after: left;
page: no-chapter;
h2, h3, h4, h5, h6 {
bookmark-level: none;
}
h2 {
font-size: 20pt;
font-weight: 400;
Expand Down Expand Up @@ -334,4 +338,11 @@ html body article {
p {
text-align: justify;
}
blockquote {
margin-left: .2cm;
padding-left: .2cm;
color: $lightTextColor;
border-left: .1cm solid;
border-color: $lightTextColor;
}
}
37 changes: 24 additions & 13 deletions mkpdfs_mkdocs/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from mkpdfs_mkdocs.utils import gen_address
from .utils import is_external
from mkpdfs_mkdocs.preprocessor import get_separate as prep_separate, get_combined as prep_combined
from mkpdfs_mkdocs.preprocessor import nest_heading_bookmarks
from mkpdfs_mkdocs.preprocessor import remove_header_links
from mkpdfs_mkdocs.preprocessor import remove_material_header_icons

log = logging.getLogger(__name__)

Expand All @@ -26,6 +29,7 @@ def __init__(self):
self.generate = True
self._articles = {}
self._page_order = []
self._page_nesting = {}
self._base_urls = {}
self._toc = None
self.html = BeautifulSoup('<html><head></head>\
Expand Down Expand Up @@ -67,17 +71,20 @@ def add_nav(self, nav):
for p in nav:
self.add_to_order(p)

def add_to_order(self, page):
def add_to_order(self, page, level=1):
if page.is_page and page.meta and 'pdf' in page.meta and not page.meta['pdf']:
return
if page.is_page:
self._page_nesting[page.file.url] = level - 1
self._page_order.append(page.file.url)
elif page.children:
uuid = str(uuid4())
self._page_order.append(uuid)
title = self.html.new_tag('h1',
id='{}-title'.format(uuid),
**{'class': 'section_title'}
**{'class': 'section_title',
# See also nest_heading_bookmarks()
'style': 'bookmark-level:{}'.format(level)}
)
title.append(page.title)
article = self.html.new_tag('article',
Expand All @@ -87,7 +94,7 @@ def add_to_order(self, page):
article.append(title)
self._articles[uuid] = article
for child in page.children:
self.add_to_order(child)
self.add_to_order(child, level=level + 1)

def remove_from_order(self, item):
return
Expand All @@ -108,7 +115,13 @@ def add_article(self, content, page, base_url):
if not article:
self.generate = False
return None
if self.mkdconfig['theme'].name == 'material':
article = remove_material_header_icons(article)
article = prep_combined(article, base_url, page.file.url)
article = remove_header_links(article)
article = nest_heading_bookmarks(
article, self._page_nesting.get(page.file.url, 0)
)
if page.meta and 'pdf' in page.meta and not page.meta['pdf']:
# print(page.meta)
return self.get_path_to_pdf(page.file.dest_path)
Expand All @@ -131,12 +144,6 @@ def add_head(self):
self.html.head.clear()
self.html.head.insert(0, head)

def get_path_to_pdf(self, start):
pdf_split = os.path.split(self.config['output_path'])
start_dir = os.path.split(start)[0]
return os.path.join(os.path.relpath(pdf_split[0],
start_dir), pdf_split[1])

def add_tocs(self):
title = self.html.new_tag('h1', id='toc-title')
title.insert(0, self.config['toc_title'])
Expand Down Expand Up @@ -178,17 +185,21 @@ def gen_articles(self):
self.add_tocs()

def get_path_to_pdf(self, start):
pdf_split = os.path.split(self.config['output_path'])
start_dir = os.path.split(start)[0] if os.path.split(start)[0] else '.'
return os.path.join(os.path.relpath(pdf_split[0], start_dir),
pdf_split[1])
return os.path.relpath(self.config['output_path'],
os.path.dirname(start))

def _gen_toc_section(self, section):
if section.children: # External Links do not have children
for p in section.children:
if p.is_page and p.meta and 'pdf' \
in p.meta and not p.meta['pdf']:
continue
if p.is_section:
h3 = self.html.new_tag('h3')
h3.insert(0, p.title)
self._toc.append(h3)
self._gen_toc_section(p)
continue
if not hasattr(p, 'file'):
# Skip external links
continue
Expand Down
9 changes: 7 additions & 2 deletions mkpdfs_mkdocs/mkpdfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from weasyprint import HTML, urls, CSS
from mkpdfs_mkdocs.generator import Generator
from mkpdfs_mkdocs.utils import modify_html
from mkpdfs_mkdocs.utils import modify_html, modify_html_material

log = logging.getLogger(__name__)

Expand All @@ -27,6 +27,7 @@ def __init__(self):
self.generator = Generator()
self._skip_pdf = True if os.environ.get("SKIP_PDF") else False
self._logger = logging.getLogger('mkdocs.mkpdfs')
self.theme = ''

def on_serve(self, server, config, **kwargs):
if self._skip_pdf:
Expand All @@ -42,6 +43,7 @@ def on_config(self, config, **kwargs):
return config
self.config['output_path'] = os.path.join("pdf", "combined.pdf") if not self.config['output_path'] else self.config['output_path']
self.generator.set_config(self.config, config)
self.theme = config['theme'].name
return config

def on_nav(self, nav, config, **kwargs):
Expand All @@ -65,7 +67,10 @@ def on_post_page(self, output_content, page, config, **kwargs):
base_url = urls.path2url(os.path.join(path, filename))
pdf_url = self.generator.add_article(output_content, page, base_url)
if self.config['pdf_links'] and pdf_url:
output_content = modify_html(output_content,pdf_url)
if self.theme == 'material':
output_content = modify_html_material(output_content, pdf_url)
else:
output_content = modify_html(output_content, pdf_url)
return output_content

def on_post_build(self, config):
Expand Down
8 changes: 7 additions & 1 deletion mkpdfs_mkdocs/preprocessor/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
from .prep import get_combined, get_separate
from .prep import (
get_combined,
get_separate,
nest_heading_bookmarks,
remove_header_links,
remove_material_header_icons,
)
31 changes: 31 additions & 0 deletions mkpdfs_mkdocs/preprocessor/prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,34 @@ def get_separate(soup: BeautifulSoup, base_url: str):

soup = replace_asset_hrefs(soup, base_url)
return soup

def remove_material_header_icons(soup: BeautifulSoup):
"""Removes links added to article headers by material theme such as the
page edit link/url (pencil icon)."""
# see https://github.com/squidfunk/mkdocs-material/issues/1920
# for justification of why this CSS class is used
for a in soup.find_all('a', **{'class': 'md-content__button'}):
a.decompose()
return soup

def remove_header_links(soup: BeautifulSoup):
for a in soup.find_all('a', **{'class': 'headerlink'}):
a.decompose()
return soup

def nest_heading_bookmarks(soup: BeautifulSoup, inc: int):
"""Ensure titles & subheadings of pages are properly nested as bookmarks.

So that while a page's titles always starts as <h1>,
when seen in the PDF index, all page headings will be nested according
to the page's nesting under sections & subsections.
"""
if not inc:
return soup
assert isinstance(inc, int) and inc > 0
for i in range(6, 0, -1):
# For each level of heading, add an inline CSS style that sets the
# bookmark-level to the heading level + `inc`.
for h in soup.find_all('h{}'.format(i)):
h['style'] = 'bookmark-level:{}'.format(i + inc)
return soup
11 changes: 11 additions & 0 deletions mkpdfs_mkdocs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ def modify_html(html: str, href: str) -> str:
return str(soup)


def modify_html_material(html: str, href: str) -> str:
# Taken from mkdocs-pdf-export-plugin for material theme.
# https://github.com/zhaoterryy/mkdocs-pdf-export-plugin/blob/46af862318c92996913a81cab07cc998a871c2cb/mkdocs_pdf_export_plugin/themes/material.py#L65-L71
a_tag = "<a class=\"md-content__button md-icon\" download href=\"%s\" title=\"PDF Export\">" % href
icon = '<svg style="height: 1.2rem; width: 1.2rem;" viewBox="0 0 384 512" xmlns="http://www.w3.org/2000/svg"><path d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm76.45 211.36l-96.42 95.7c-6.65 6.61-17.39 6.61-24.04 0l-96.42-95.7C73.42 337.29 80.54 320 94.82 320H160v-80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v80h65.18c14.28 0 21.4 17.29 11.27 27.36zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z"></path></svg>'
button_tag = a_tag + icon + "</a>"
insert_point = "<article class=\"md-content__inner md-typeset\">"
html = html.replace(insert_point, insert_point + button_tag)
return html


def gen_address(config):
soup = BeautifulSoup('<body></body>',
'html5lib'
Expand Down