# -*- coding: utf-8 -*-
"""
sphinx.builders.epub3
~~~~~~~~~~~~~~~~~~~~~
Build epub3 files.
Originally derived from epub.py.
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import codecs
from os import path
from sphinx.builders.epub import EpubBuilder
# (Fragment) templates from which the metainfo files content.opf, toc.ncx,
# mimetype, and META-INF/container.xml are created.
# This template section also defines strings that are embedded in the html
# output but that may be customized by (re-)setting module attributes,
# e.g. from conf.py.
NAVIGATION_DOC_TEMPLATE = u'''\
%(toc_locale)s
%(toc_locale)s
%(navlist)s
'''
NAVLIST_TEMPLATE = u'''\
%(indent)s
%(indent)s %(text)s
%(indent)s
'''
NAVLIST_INDENT = ' '
PACKAGE_DOC_TEMPLATE = u'''\
%(lang)s
%(title)s
%(description)s
%(author)s
%(contributor)s
%(publisher)s
%(copyright)s
%(id)s
%(date)s
%(date)s
%(files)s
%(spine)s
%(guide)s
'''
# The epub3 publisher
class Epub3Builder(EpubBuilder):
"""
Builder that outputs epub3 files.
It creates the metainfo files content.opf, nav.xhtml, toc.ncx, mimetype,
and META-INF/container.xml. Afterwards, all necessary files are zipped to
an epub file.
"""
name = 'epub3'
navigation_doc_template = NAVIGATION_DOC_TEMPLATE
navlist_template = NAVLIST_TEMPLATE
navlist_indent = NAVLIST_INDENT
content_template = PACKAGE_DOC_TEMPLATE
# Finish by building the epub file
def handle_finish(self):
"""Create the metainfo files and finally the epub."""
self.get_toc()
self.build_mimetype(self.outdir, 'mimetype')
self.build_container(self.outdir, 'META-INF/container.xml')
self.build_content(self.outdir, 'content.opf')
self.build_navigation_doc(self.outdir, 'nav.xhtml')
self.build_toc(self.outdir, 'toc.ncx')
self.build_epub(self.outdir, self.config.epub_basename + '.epub')
def content_metadata(self, files, spine, guide):
"""Create a dictionary with all metadata for the content.opf
file properly escaped.
"""
metadata = super(Epub3Builder, self).content_metadata(
files, spine, guide)
metadata['description'] = self.esc(self.config.epub3_description)
metadata['contributor'] = self.esc(self.config.epub3_contributor)
metadata['page_progression_direction'] = self.esc(
self.config.epub3_page_progression_direction) or 'default'
return metadata
def new_navlist(self, node, level):
"""Create a new entry in the toc from the node at given level."""
# XXX Modifies the node
self.tocid += 1
node['indent'] = self.navlist_indent * level
navpoint = self.navlist_template % node
return navpoint
def build_navlist(self, nodes):
"""Create the toc navigation structure.
This method is almost same as build_navpoints method in epub.py.
This is because the logical navigation structure of epub3 is not
different from one of epub2.
The difference from build_navpoints method is templates which are used
when generating navigation documents.
"""
navstack = []
navlist = []
level = 1
lastnode = None
for node in nodes:
if not node['text']:
continue
file = node['refuri'].split('#')[0]
if file in self.ignored_files:
continue
if node['level'] > self.config.epub_tocdepth:
continue
if node['level'] == level:
navlist.append(self.new_navlist(node, level))
elif node['level'] == level + 1:
navstack.append(navlist)
navlist = []
level += 1
if lastnode and self.config.epub_tocdup:
navlist.append(self.new_navlist(node, level))
navlist[-1] = '\n' + navlist[-1]
else:
while node['level'] < level:
subnav = '\n'.join(navlist)
navlist = navstack.pop()
navlist[-1] = self.insert_subnav(navlist[-1], subnav)
level -= 1
navlist[-1] = navlist[-1] + ' '
navlist.append(self.new_navlist(node, level))
lastnode = node
while level != 1:
subnav = '\n'.join(navlist)
navlist = navstack.pop()
navlist[-1] = self.insert_subnav(navlist[-1], subnav)
level -= 1
navlist[-1] = navlist[-1] + ''
return '\n'.join(navlist)
def navigation_doc_metadata(self, navlist):
"""Create a dictionary with all metadata for the nav.xhtml file
properly escaped.
"""
metadata = {}
metadata['lang'] = self.esc(self.config.epub_language)
metadata['toc_locale'] = self.esc(self.guide_titles['toc'])
metadata['navlist'] = navlist
return metadata
def build_navigation_doc(self, outdir, outname):
"""Write the metainfo file nav.xhtml."""
self.info('writing %s file...' % outname)
if self.config.epub_tocscope == 'default':
doctree = self.env.get_and_resolve_doctree(
self.config.master_doc, self,
prune_toctrees=False, includehidden=False)
refnodes = self.get_refnodes(doctree, [])
self.toc_add_files(refnodes)
else:
# 'includehidden'
refnodes = self.refnodes
navlist = self.build_navlist(refnodes)
f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
try:
f.write(self.navigation_doc_template %
self.navigation_doc_metadata(navlist))
finally:
f.close()
# Add nav.xhtml to epub file
self.files.append(outname)