Merge pull request #11 from RealOrangeOne/toc

Table of Contents
This commit is contained in:
Jake Howard 2017-05-24 13:40:16 +01:00 committed by GitHub
commit a37b08ab4d
13 changed files with 147 additions and 28 deletions

3
.gitignore vendored
View file

@ -246,6 +246,9 @@ ENV/
out/ out/
md_pdf/assets/templates/cover.html 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/static/style.css
md_pdf/assets/csl/ md_pdf/assets/csl/
md_pdf/assets/styles-master/ md_pdf/assets/styles-master/

View file

@ -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;
}
}
}

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:outline="http://wkhtmltopdf.org/outline"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="outline:outline">
<html>
<head>
<link rel="stylesheet" href="{{ static_dir }}/style.css" />
</head>
<body class="tocs">
<h1>Table of Contents</h1>
<ul>
<xsl:apply-templates select="outline:item/outline:item"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="outline:item">
<li>
<xsl:if test="@page!='2' and @title!='References'">
<div class="row">
<a class="title">
<xsl:if test="@link">
<xsl:attribute name="href">
<xsl:value-of select="@link"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="@backLink">
<xsl:attribute name="name">
<xsl:value-of select="@backLink"/>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="@title" />
</a>
<span class="page-number">
<xsl:value-of select="@page" />
</span>
</div>
</xsl:if>
<ul>
<xsl:apply-templates select="outline:item"/>
</ul>
</li>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,9 +1,9 @@
from md_pdf.build.md import read_files from md_pdf.build.md import read_files
from md_pdf.build.pandoc import build_document, output_html 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.css import render_css
from md_pdf.build.pdf import export_pdf 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 os
import logging import logging
import time import time
@ -20,7 +20,7 @@ def build(config):
if 'html' in config['output_formats']: if 'html' in config['output_formats']:
output_html(parsed_template, os.path.abspath(config['output_dir'])) output_html(parsed_template, os.path.abspath(config['output_dir']))
if 'pdf' in config['output_formats']: if 'pdf' in config['output_formats']:
render_cover(config) render_templates(config)
render_css() render_css()
export_pdf(parsed_template, config) export_pdf(parsed_template, config)
logger.info('Output completed in {:.2f} seconds.'.format(time.time() - start_time)) logger.info('Output completed in {:.2f} seconds.'.format(time.time() - start_time))

View file

@ -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

View file

@ -1,6 +1,6 @@
import pdfkit import pdfkit
from md_pdf.consts import TEMPLATES_DIR, STATIC_DIR 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 os
import logging import logging
@ -14,6 +14,11 @@ DEFAULT_MARGIN_HORIZONTAL = '2.5cm'
STYLE_FILE = os.path.join(STATIC_DIR, 'style.css') STYLE_FILE = os.path.join(STATIC_DIR, 'style.css')
HEADER_FILE = os.path.join(TEMPLATES_DIR, 'header.html') HEADER_FILE = os.path.join(TEMPLATES_DIR, 'header.html')
FOOTER_FILE = os.path.join(TEMPLATES_DIR, 'footer.html') FOOTER_FILE = os.path.join(TEMPLATES_DIR, 'footer.html')
TOC_OPTIONS = {
'xsl-style-sheet': os.path.join(TEMPLATES_DIR, 'toc.xsl')
}
PDF_OPTIONS = { PDF_OPTIONS = {
"no-pdf-compression": "", "no-pdf-compression": "",
"enable-internal-links": "", "enable-internal-links": "",
@ -43,5 +48,7 @@ def export_pdf(content, config):
content, content,
os.path.join(os.path.abspath(config['output_dir']), 'output.pdf'), os.path.join(os.path.abspath(config['output_dir']), 'output.pdf'),
options=PDF_OPTIONS, options=PDF_OPTIONS,
cover=OUTPUT_COVER_FILE cover=FILE_NAME_FORMAT.format('cover'),
toc=TOC_OPTIONS if config['toc'] else {},
cover_first=True
) )

38
md_pdf/build/templates.py Normal file
View file

@ -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)

View file

@ -69,12 +69,22 @@ def validate_context(config):
raise ConfigValidationException("Context keys must be plain. Invalid values: {}".format(", ".join(invalid_values))) 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): def validate_config(config):
logger.debug("Validating Config...")
for validator in [ for validator in [
check_required_keys, check_required_keys,
test_input, test_input,
test_output, test_output,
validate_bibliography, validate_bibliography,
validate_context validate_context,
validate_toc
]: ]:
validator(config) validator(config)
logger.debug("Config Ok!")

View file

@ -21,3 +21,6 @@
- Citation with suffix only [@item1 and nowhere else]. - Citation with suffix only [@item1 and nowhere else].
- With some markup [*see* @item1 p. **32**]. - With some markup [*see* @item1 p. **32**].
##### More referencing tests

View file

@ -12,3 +12,4 @@ context:
student_number: 123456 student_number: 123456
turnitin_number: 789123 turnitin_number: 789123
title: test title title: test title
toc: true