diff --git a/.gitignore b/.gitignore index d1ac150..edd2d08 100644 --- a/.gitignore +++ b/.gitignore @@ -246,6 +246,9 @@ ENV/ out/ md_pdf/assets/templates/cover.html +md_pdf/assets/templates/header.html +md_pdf/assets/templates/footer.html +md_pdf/assets/templates/toc.xsl md_pdf/assets/static/style.css md_pdf/assets/csl/ md_pdf/assets/styles-master/ diff --git a/md_pdf/assets/static/style.scss b/md_pdf/assets/static/style.scss index bf57eaa..522df91 100644 --- a/md_pdf/assets/static/style.scss +++ b/md_pdf/assets/static/style.scss @@ -58,3 +58,35 @@ body.footer, body.header { } } } + + +body.tocs { + h1 { + margin-bottom: 45px; + text-align: center; + } + + .row { + margin-bottom: $font-size-base; + border-bottom: 1px dashed black; + font-size: $font-size-base * 1.5; + } + + .page-number { + float: right; + padding-right: $font-size-base * 0.5; + } + + + ul { + padding-left: 0; + + li { + list-style: none; + } + + ul { + padding-left: $font-size-base; + } + } +} diff --git a/md_pdf/assets/templates/footer.html b/md_pdf/assets/templates/footer-template.html similarity index 100% rename from md_pdf/assets/templates/footer.html rename to md_pdf/assets/templates/footer-template.html diff --git a/md_pdf/assets/templates/header.html b/md_pdf/assets/templates/header-template.html similarity index 100% rename from md_pdf/assets/templates/header.html rename to md_pdf/assets/templates/header-template.html diff --git a/md_pdf/assets/templates/toc-template.xsl b/md_pdf/assets/templates/toc-template.xsl new file mode 100644 index 0000000..f7ad75d --- /dev/null +++ b/md_pdf/assets/templates/toc-template.xsl @@ -0,0 +1,47 @@ + + + + + + + + +

Table of Contents

+ + + +
+ +
  • + + + +
      + +
    +
  • +
    +
    diff --git a/md_pdf/build/__init__.py b/md_pdf/build/__init__.py index 5b9f885..29a47d8 100644 --- a/md_pdf/build/__init__.py +++ b/md_pdf/build/__init__.py @@ -1,9 +1,9 @@ from md_pdf.build.md import read_files from md_pdf.build.pandoc import build_document, output_html -from md_pdf.build.cover import render_cover +from md_pdf.build.templates import render_templates from md_pdf.build.css import render_css from md_pdf.build.pdf import export_pdf -from md_pdf.build.template import parse_template +from md_pdf.build.content import parse_template import os import logging import time @@ -20,7 +20,7 @@ def build(config): if 'html' in config['output_formats']: output_html(parsed_template, os.path.abspath(config['output_dir'])) if 'pdf' in config['output_formats']: - render_cover(config) + render_templates(config) render_css() export_pdf(parsed_template, config) logger.info('Output completed in {:.2f} seconds.'.format(time.time() - start_time)) diff --git a/md_pdf/build/template.py b/md_pdf/build/content.py similarity index 100% rename from md_pdf/build/template.py rename to md_pdf/build/content.py diff --git a/md_pdf/build/cover.py b/md_pdf/build/cover.py deleted file mode 100644 index dc3b3d5..0000000 --- a/md_pdf/build/cover.py +++ /dev/null @@ -1,22 +0,0 @@ -from jinja2 import Template -from md_pdf.consts import TEMPLATES_DIR -import os -import logging - -logger = logging.getLogger(__file__) - - -COVER_TEMPLATE = os.path.join(TEMPLATES_DIR, 'cover-template.html') -OUTPUT_COVER_FILE = os.path.join(TEMPLATES_DIR, 'cover.html') - - -def render_cover(config): - logger.debug("Rendering Cover...") - context = config['context'].copy() - context['title'] = config['title'] - with open(COVER_TEMPLATE) as f: - template = Template(f.read()) - with open(OUTPUT_COVER_FILE, "w") as f: - cover = template.render(context) - f.write(cover) - return cover diff --git a/md_pdf/build/pdf.py b/md_pdf/build/pdf.py index 12d7352..b498b5d 100644 --- a/md_pdf/build/pdf.py +++ b/md_pdf/build/pdf.py @@ -1,6 +1,6 @@ import pdfkit from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR -from md_pdf.build.cover import OUTPUT_COVER_FILE +from md_pdf.build.templates import FILE_NAME_FORMAT import os import logging @@ -14,6 +14,11 @@ DEFAULT_MARGIN_HORIZONTAL = '2.5cm' STYLE_FILE = os.path.join(STATIC_DIR, 'style.css') HEADER_FILE = os.path.join(TEMPLATES_DIR, 'header.html') FOOTER_FILE = os.path.join(TEMPLATES_DIR, 'footer.html') + +TOC_OPTIONS = { + 'xsl-style-sheet': os.path.join(TEMPLATES_DIR, 'toc.xsl') +} + PDF_OPTIONS = { "no-pdf-compression": "", "enable-internal-links": "", @@ -43,5 +48,7 @@ def export_pdf(content, config): content, os.path.join(os.path.abspath(config['output_dir']), 'output.pdf'), options=PDF_OPTIONS, - cover=OUTPUT_COVER_FILE + cover=FILE_NAME_FORMAT.format('cover'), + toc=TOC_OPTIONS if config['toc'] else {}, + cover_first=True ) diff --git a/md_pdf/build/templates.py b/md_pdf/build/templates.py new file mode 100644 index 0000000..3c8c4ef --- /dev/null +++ b/md_pdf/build/templates.py @@ -0,0 +1,38 @@ +from jinja2 import Template +from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR +import os +import logging + +logger = logging.getLogger(__file__) + +EXTRA_CONFIG = { + 'templates_dir': TEMPLATES_DIR, + 'static_dir': STATIC_DIR +} + +FILE_NAME_FORMAT = os.path.join(TEMPLATES_DIR, "{}.html") +TEMPLATE_FORMAT = os.path.join(TEMPLATES_DIR, "{}-template.html") + + +def render_page(input_file, output_file, context): + logger.debug("Rendering {}...".format(os.path.splitext(os.path.basename(output_file))[0].title())) + with open(input_file) as f: + template = Template(f.read()) + with open(output_file, "w") as f: + cover = template.render(context) + f.write(cover) + return cover + + +def render_templates(config): + context = config['context'].copy() + context['title'] = config['title'] + context = dict(context, **EXTRA_CONFIG) + for template in [ + 'cover', + 'header', + 'footer' + ]: + render_page(TEMPLATE_FORMAT.format(template), FILE_NAME_FORMAT.format(template), context) + if config.get('toc', False): + render_page(os.path.join(TEMPLATES_DIR, 'toc-template.xsl'), os.path.join(TEMPLATES_DIR, 'toc.xsl'), context) diff --git a/md_pdf/config/validate.py b/md_pdf/config/validate.py index a9d5623..d7e0199 100644 --- a/md_pdf/config/validate.py +++ b/md_pdf/config/validate.py @@ -69,12 +69,22 @@ def validate_context(config): raise ConfigValidationException("Context keys must be plain. Invalid values: {}".format(", ".join(invalid_values))) +def validate_toc(config): + if 'toc' not in config: + return + if type(config['toc']) != bool: + raise ConfigValidationException("Table of contents key should be either true or false") + + def validate_config(config): + logger.debug("Validating Config...") for validator in [ check_required_keys, test_input, test_output, validate_bibliography, - validate_context + validate_context, + validate_toc ]: validator(config) + logger.debug("Config Ok!") diff --git a/test-files/2-pandoc.md b/test-files/2-pandoc.md index e248668..ba44409 100644 --- a/test-files/2-pandoc.md +++ b/test-files/2-pandoc.md @@ -21,3 +21,6 @@ - Citation with suffix only [@item1 and nowhere else]. - With some markup [*see* @item1 p. **32**]. + + +##### More referencing tests diff --git a/test-files/mdp.yml b/test-files/mdp.yml index 411e971..661ce22 100644 --- a/test-files/mdp.yml +++ b/test-files/mdp.yml @@ -12,3 +12,4 @@ context: student_number: 123456 turnitin_number: 789123 title: test title +toc: true