From 5d8d327b1397bfb71875379346fe3d70eb59b2b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bla=C5=BEej?= Date: Sat, 16 May 2020 13:25:32 +0200 Subject: [PATCH 1/9] add nested sections to TOC This reintroduces commit d26b56e36577f04c243aab2b1e455da375ea7e20 That commit was previously merged to master with PR #21 to fix issue #4. But subsequently, MR #26 undid the change. As far as I can tell this happened by mistake during merge/rebase and conflict resolutions. --- mkpdfs_mkdocs/generator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mkpdfs_mkdocs/generator.py b/mkpdfs_mkdocs/generator.py index 9be961c..975470b 100644 --- a/mkpdfs_mkdocs/generator.py +++ b/mkpdfs_mkdocs/generator.py @@ -189,6 +189,12 @@ def _gen_toc_section(self, section): 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 From 35c3286d090e3e7fb8993af66cf46d6b40073ab9 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Thu, 30 Jul 2020 20:52:24 +0300 Subject: [PATCH 2/9] Fix get_path_to_pdf 1. Remove duplicate declaration of `get_path_to_pdf`. 2. Properly handle `output_path` with no dir part (eg `docs.pdf`). This properly resolves issue #27 that wasn't actually fixed with 5d30cdd3a1c8fad23b539156d68376428a62b26e. 3. Fix relative link to PDF It had on `..` too many. This did't manifest as a problem when a site was deployed directly on a hostname but when deployed under a subdirectory, the PDF link wouldn't resolve. --- mkpdfs_mkdocs/generator.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/mkpdfs_mkdocs/generator.py b/mkpdfs_mkdocs/generator.py index 975470b..3f2a034 100644 --- a/mkpdfs_mkdocs/generator.py +++ b/mkpdfs_mkdocs/generator.py @@ -131,12 +131,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']) @@ -178,10 +172,8 @@ 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 From 938671e7d8578feb6821aa7b03daf07f533b4533 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Fri, 18 Sep 2020 01:41:46 +0300 Subject: [PATCH 3/9] Add CSS for styling blockquotes Very simple styling, blockquotes appear in lighter color, indented, and with a bar running down its left side. --- mkpdfs_mkdocs/design/report.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mkpdfs_mkdocs/design/report.scss b/mkpdfs_mkdocs/design/report.scss index 0d3b41d..48953e7 100644 --- a/mkpdfs_mkdocs/design/report.scss +++ b/mkpdfs_mkdocs/design/report.scss @@ -4,6 +4,7 @@ $bgColor: #2196f3; $bgTextColor: #fff; +$lightTextColor: #707070; @font-face { @@ -334,4 +335,11 @@ html body article { p { text-align: justify; } + blockquote { + margin-left: .2cm; + padding-left: .2cm; + color: $lightTextColor; + border-left: .1cm solid; + border-color: $lightTextColor; + } } From 0c21314fa9e857cfcb4eecd323bb43a2a0a81a69 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Thu, 30 Jul 2020 20:11:42 +0300 Subject: [PATCH 4/9] Don't display all TOC sections in the bookmarks index If one can see the bookmarks index in the PDF viewer, seeing all of the TOC sections there just clutters the index. --- mkpdfs_mkdocs/design/report.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mkpdfs_mkdocs/design/report.scss b/mkpdfs_mkdocs/design/report.scss index 48953e7..3df4db3 100644 --- a/mkpdfs_mkdocs/design/report.scss +++ b/mkpdfs_mkdocs/design/report.scss @@ -277,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; From 939efbe0fe2f2f81bfb3425ba58a116d56a8c84e Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Thu, 30 Jul 2020 20:20:50 +0300 Subject: [PATCH 5/9] =?UTF-8?q?Remove=20headerlinks=20(=C2=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that they do not appear in page headings. --- mkpdfs_mkdocs/generator.py | 2 ++ mkpdfs_mkdocs/preprocessor/__init__.py | 6 +++++- mkpdfs_mkdocs/preprocessor/prep.py | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mkpdfs_mkdocs/generator.py b/mkpdfs_mkdocs/generator.py index 3f2a034..72f4dd9 100644 --- a/mkpdfs_mkdocs/generator.py +++ b/mkpdfs_mkdocs/generator.py @@ -10,6 +10,7 @@ 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 remove_header_links log = logging.getLogger(__name__) @@ -109,6 +110,7 @@ def add_article(self, content, page, base_url): self.generate = False return None article = prep_combined(article, base_url, page.file.url) + article = remove_header_links(article) 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) diff --git a/mkpdfs_mkdocs/preprocessor/__init__.py b/mkpdfs_mkdocs/preprocessor/__init__.py index 8fa23fa..898de02 100755 --- a/mkpdfs_mkdocs/preprocessor/__init__.py +++ b/mkpdfs_mkdocs/preprocessor/__init__.py @@ -1 +1,5 @@ -from .prep import get_combined, get_separate \ No newline at end of file +from .prep import ( + get_combined, + get_separate, + remove_header_links, +) diff --git a/mkpdfs_mkdocs/preprocessor/prep.py b/mkpdfs_mkdocs/preprocessor/prep.py index 45b8c83..9af0294 100755 --- a/mkpdfs_mkdocs/preprocessor/prep.py +++ b/mkpdfs_mkdocs/preprocessor/prep.py @@ -28,3 +28,8 @@ def get_separate(soup: BeautifulSoup, base_url: str): soup = replace_asset_hrefs(soup, base_url) return soup + +def remove_header_links(soup: BeautifulSoup): + for a in soup.find_all('a', **{'class': 'headerlink'}): + a.decompose() + return soup From 0557adbeec83cbae7dc46f05d8a97569364a99a3 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Sun, 13 Sep 2020 20:12:20 +0300 Subject: [PATCH 6/9] Remove page edit & other links added by material theme For example the page edit link (pencil icon) and any other links added by material theme on the right of the page header, inside the article content. Without this change, there'd be no icon but the entire URL for editing the page would be included in the PDF above each page title which was undesired. Filtering of such links is based on the `md-content__button` class as suggested in https://github.com/squidfunk/mkdocs-material/issues/1920 --- mkpdfs_mkdocs/generator.py | 3 +++ mkpdfs_mkdocs/preprocessor/__init__.py | 1 + mkpdfs_mkdocs/preprocessor/prep.py | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/mkpdfs_mkdocs/generator.py b/mkpdfs_mkdocs/generator.py index 72f4dd9..ce232f8 100644 --- a/mkpdfs_mkdocs/generator.py +++ b/mkpdfs_mkdocs/generator.py @@ -11,6 +11,7 @@ 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 remove_header_links +from mkpdfs_mkdocs.preprocessor import remove_material_header_icons log = logging.getLogger(__name__) @@ -109,6 +110,8 @@ 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) if page.meta and 'pdf' in page.meta and not page.meta['pdf']: diff --git a/mkpdfs_mkdocs/preprocessor/__init__.py b/mkpdfs_mkdocs/preprocessor/__init__.py index 898de02..080b059 100755 --- a/mkpdfs_mkdocs/preprocessor/__init__.py +++ b/mkpdfs_mkdocs/preprocessor/__init__.py @@ -2,4 +2,5 @@ get_combined, get_separate, remove_header_links, + remove_material_header_icons, ) diff --git a/mkpdfs_mkdocs/preprocessor/prep.py b/mkpdfs_mkdocs/preprocessor/prep.py index 9af0294..cf51e66 100755 --- a/mkpdfs_mkdocs/preprocessor/prep.py +++ b/mkpdfs_mkdocs/preprocessor/prep.py @@ -29,6 +29,15 @@ 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() From 80dc2c53cf6ad353a6ebb3541d1676d63e2ad090 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Mon, 3 Aug 2020 11:14:14 +0300 Subject: [PATCH 7/9] Use dedicated PDF link/icon for material theme --- mkpdfs_mkdocs/mkpdfs.py | 9 +++++++-- mkpdfs_mkdocs/utils.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mkpdfs_mkdocs/mkpdfs.py b/mkpdfs_mkdocs/mkpdfs.py index e88b3a3..0b80dba 100644 --- a/mkpdfs_mkdocs/mkpdfs.py +++ b/mkpdfs_mkdocs/mkpdfs.py @@ -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__) @@ -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: @@ -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): @@ -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): diff --git a/mkpdfs_mkdocs/utils.py b/mkpdfs_mkdocs/utils.py index 3c200c8..ea5293c 100644 --- a/mkpdfs_mkdocs/utils.py +++ b/mkpdfs_mkdocs/utils.py @@ -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 = "" % href + icon = '' + button_tag = a_tag + icon + "" + insert_point = "
" + html = html.replace(insert_point, insert_point + button_tag) + return html + + def gen_address(config): soup = BeautifulSoup('', 'html5lib' From 8648a0b6ff359f078db8edac13d81130ee09e7b0 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Sun, 13 Sep 2020 20:15:26 +0300 Subject: [PATCH 8/9] Add vim swap files to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7c33115..07e5363 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ site report.css build venv +.*.sw[pon] From 69b0e5d9d9b81e40e563b2141ab65cc69659cf92 Mon Sep 17 00:00:00 2001 From: Dimitris Rozakis Date: Thu, 30 Jul 2020 19:59:31 +0300 Subject: [PATCH 9/9] Properly nest all headings for correct bookmarks index All sections and articles would start with a

which would mess up the autogenerated bookmarks index displayed by the PDF viewer. Initially I experimented with increasing the heading levels of a page based on how deeply nested under subsections the page is. This had some issues: 1. If a page was nested under N sections/dirs and used headings up to level L where N + L > 6, the headings' level couldn't be increased any more. I resorted to transforming them to ``. 1. Pages were now themed differently. The title of a page would be an `

` if on top level, `

` if under a top level section, `

` if under a subsection and so on. 1. The top page banner that indicates the current document would just display the top level section for non top-level pages. In the end I decided that it's best to not mess with the heading levels of pages, just with their nesting in the PDF's bookmark index. This was achieved via the use of the `bookmark-level` CSS property. Therefore this commit shouldn't affect the contents of the output PDF at all, just the nesting of the pages & sections in its bookmark index. --- mkpdfs_mkdocs/generator.py | 14 +++++++++++--- mkpdfs_mkdocs/preprocessor/__init__.py | 1 + mkpdfs_mkdocs/preprocessor/prep.py | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/mkpdfs_mkdocs/generator.py b/mkpdfs_mkdocs/generator.py index ce232f8..0a77306 100644 --- a/mkpdfs_mkdocs/generator.py +++ b/mkpdfs_mkdocs/generator.py @@ -10,6 +10,7 @@ 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 @@ -28,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('\ @@ -69,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', @@ -89,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 @@ -114,6 +119,9 @@ def add_article(self, content, page, base_url): 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) diff --git a/mkpdfs_mkdocs/preprocessor/__init__.py b/mkpdfs_mkdocs/preprocessor/__init__.py index 080b059..20cddb6 100755 --- a/mkpdfs_mkdocs/preprocessor/__init__.py +++ b/mkpdfs_mkdocs/preprocessor/__init__.py @@ -1,6 +1,7 @@ from .prep import ( get_combined, get_separate, + nest_heading_bookmarks, remove_header_links, remove_material_header_icons, ) diff --git a/mkpdfs_mkdocs/preprocessor/prep.py b/mkpdfs_mkdocs/preprocessor/prep.py index cf51e66..a7a2c4f 100755 --- a/mkpdfs_mkdocs/preprocessor/prep.py +++ b/mkpdfs_mkdocs/preprocessor/prep.py @@ -42,3 +42,20 @@ 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

, + 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