mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
epub: Add template for tox.ncx
This commit is contained in:
parent
fa6cc544ee
commit
a051fe2c6d
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import codecs
|
|
||||||
import zipfile
|
import zipfile
|
||||||
from os import path
|
from os import path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -52,35 +51,6 @@ logger = logging.getLogger(__name__)
|
|||||||
# output but that may be customized by (re-)setting module attributes,
|
# output but that may be customized by (re-)setting module attributes,
|
||||||
# e.g. from conf.py.
|
# e.g. from conf.py.
|
||||||
|
|
||||||
TOC_TEMPLATE = u'''\
|
|
||||||
<?xml version="1.0"?>
|
|
||||||
<ncx version="2005-1" xmlns="http://www.daisy.org/z3986/2005/ncx/">
|
|
||||||
<head>
|
|
||||||
<meta name="dtb:uid" content="%(uid)s"/>
|
|
||||||
<meta name="dtb:depth" content="%(level)d"/>
|
|
||||||
<meta name="dtb:totalPageCount" content="0"/>
|
|
||||||
<meta name="dtb:maxPageNumber" content="0"/>
|
|
||||||
</head>
|
|
||||||
<docTitle>
|
|
||||||
<text>%(title)s</text>
|
|
||||||
</docTitle>
|
|
||||||
<navMap>
|
|
||||||
%(navpoints)s
|
|
||||||
</navMap>
|
|
||||||
</ncx>
|
|
||||||
'''
|
|
||||||
|
|
||||||
NAVPOINT_TEMPLATE = u'''\
|
|
||||||
%(indent)s <navPoint id="%(navpoint)s" playOrder="%(playorder)d">
|
|
||||||
%(indent)s <navLabel>
|
|
||||||
%(indent)s <text>%(text)s</text>
|
|
||||||
%(indent)s </navLabel>
|
|
||||||
%(indent)s <content src="%(refuri)s" />
|
|
||||||
%(indent)s </navPoint>'''
|
|
||||||
|
|
||||||
NAVPOINT_INDENT = ' '
|
|
||||||
NODE_NAVPOINT_TEMPLATE = 'navPoint%d'
|
|
||||||
|
|
||||||
COVERPAGE_NAME = u'epub-cover.xhtml'
|
COVERPAGE_NAME = u'epub-cover.xhtml'
|
||||||
|
|
||||||
TOCTREE_TEMPLATE = u'toctree-l%d'
|
TOCTREE_TEMPLATE = u'toctree-l%d'
|
||||||
@ -126,6 +96,7 @@ REFURI_RE = re.compile("([^#:]*#)(.*)")
|
|||||||
ManifestItem = namedtuple('ManifestItem', ['href', 'id', 'media_type'])
|
ManifestItem = namedtuple('ManifestItem', ['href', 'id', 'media_type'])
|
||||||
Spine = namedtuple('Spine', ['idref', 'linear'])
|
Spine = namedtuple('Spine', ['idref', 'linear'])
|
||||||
Guide = namedtuple('Guide', ['type', 'title', 'uri'])
|
Guide = namedtuple('Guide', ['type', 'title', 'uri'])
|
||||||
|
NavPoint = namedtuple('NavPoint', ['navpoint', 'playorder', 'text', 'refuri', 'children'])
|
||||||
|
|
||||||
|
|
||||||
# The epub publisher
|
# The epub publisher
|
||||||
@ -160,10 +131,6 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
|||||||
# don't generate search index or include search page
|
# don't generate search index or include search page
|
||||||
search = False
|
search = False
|
||||||
|
|
||||||
toc_template = TOC_TEMPLATE
|
|
||||||
navpoint_template = NAVPOINT_TEMPLATE
|
|
||||||
navpoint_indent = NAVPOINT_INDENT
|
|
||||||
node_navpoint_template = NODE_NAVPOINT_TEMPLATE
|
|
||||||
coverpage_name = COVERPAGE_NAME
|
coverpage_name = COVERPAGE_NAME
|
||||||
toctree_template = TOCTREE_TEMPLATE
|
toctree_template = TOCTREE_TEMPLATE
|
||||||
doctype = DOCTYPE
|
doctype = DOCTYPE
|
||||||
@ -647,20 +614,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
|||||||
if incr:
|
if incr:
|
||||||
self.playorder += 1
|
self.playorder += 1
|
||||||
self.tocid += 1
|
self.tocid += 1
|
||||||
node['indent'] = self.navpoint_indent * level
|
return NavPoint(self.esc('navPoint%d' % self.tocid), self.playorder,
|
||||||
node['navpoint'] = self.esc(self.node_navpoint_template % self.tocid)
|
node['text'], node['refuri'], [])
|
||||||
node['playorder'] = self.playorder
|
|
||||||
return self.navpoint_template % node
|
|
||||||
|
|
||||||
def insert_subnav(self, node, subnav):
|
|
||||||
# type: (nodes.Node, unicode) -> unicode
|
|
||||||
"""Insert nested navpoints for given node.
|
|
||||||
|
|
||||||
The node and subnav are already rendered to text.
|
|
||||||
"""
|
|
||||||
nlist = node.rsplit('\n', 1)
|
|
||||||
nlist.insert(-1, subnav)
|
|
||||||
return '\n'.join(nlist)
|
|
||||||
|
|
||||||
def build_navpoints(self, nodes):
|
def build_navpoints(self, nodes):
|
||||||
# type: (nodes.Node) -> unicode
|
# type: (nodes.Node) -> unicode
|
||||||
@ -669,9 +624,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
|||||||
Subelements of a node are nested inside the navpoint. For nested nodes
|
Subelements of a node are nested inside the navpoint. For nested nodes
|
||||||
the parent node is reinserted in the subnav.
|
the parent node is reinserted in the subnav.
|
||||||
"""
|
"""
|
||||||
navstack = []
|
navstack = [] # type: List[NavPoint]
|
||||||
navlist = []
|
navstack.append(NavPoint('dummy', '', '', '', []))
|
||||||
level = 1
|
level = 0
|
||||||
lastnode = None
|
lastnode = None
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if not node['text']:
|
if not node['text']:
|
||||||
@ -682,29 +637,30 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
|||||||
if node['level'] > self.config.epub_tocdepth:
|
if node['level'] > self.config.epub_tocdepth:
|
||||||
continue
|
continue
|
||||||
if node['level'] == level:
|
if node['level'] == level:
|
||||||
navlist.append(self.new_navpoint(node, level))
|
navpoint = self.new_navpoint(node, level)
|
||||||
|
navstack.pop()
|
||||||
|
navstack[-1].children.append(navpoint)
|
||||||
|
navstack.append(navpoint)
|
||||||
elif node['level'] == level + 1:
|
elif node['level'] == level + 1:
|
||||||
navstack.append(navlist)
|
|
||||||
navlist = []
|
|
||||||
level += 1
|
level += 1
|
||||||
if lastnode and self.config.epub_tocdup:
|
if lastnode and self.config.epub_tocdup:
|
||||||
# Insert starting point in subtoc with same playOrder
|
# Insert starting point in subtoc with same playOrder
|
||||||
navlist.append(self.new_navpoint(lastnode, level, False))
|
navstack[-1].children.append(self.new_navpoint(lastnode, level, False))
|
||||||
navlist.append(self.new_navpoint(node, level))
|
navpoint = self.new_navpoint(node, level)
|
||||||
|
navstack[-1].children.append(navpoint)
|
||||||
|
navstack.append(navpoint)
|
||||||
|
elif node['level'] < level:
|
||||||
|
while node['level'] < len(navstack):
|
||||||
|
navstack.pop()
|
||||||
|
level = node['level']
|
||||||
|
navpoint = self.new_navpoint(node, level)
|
||||||
|
navstack[-1].children.append(navpoint)
|
||||||
|
navstack.append(navpoint)
|
||||||
else:
|
else:
|
||||||
while node['level'] < level:
|
raise
|
||||||
subnav = '\n'.join(navlist)
|
|
||||||
navlist = navstack.pop()
|
|
||||||
navlist[-1] = self.insert_subnav(navlist[-1], subnav)
|
|
||||||
level -= 1
|
|
||||||
navlist.append(self.new_navpoint(node, level))
|
|
||||||
lastnode = node
|
lastnode = node
|
||||||
while level != 1:
|
|
||||||
subnav = '\n'.join(navlist)
|
return navstack[0].children
|
||||||
navlist = navstack.pop()
|
|
||||||
navlist[-1] = self.insert_subnav(navlist[-1], subnav)
|
|
||||||
level -= 1
|
|
||||||
return '\n'.join(navlist)
|
|
||||||
|
|
||||||
def toc_metadata(self, level, navpoints):
|
def toc_metadata(self, level, navpoints):
|
||||||
# type: (int, List[unicode]) -> Dict[unicode, Any]
|
# type: (int, List[unicode]) -> Dict[unicode, Any]
|
||||||
@ -735,8 +691,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
|||||||
navpoints = self.build_navpoints(refnodes)
|
navpoints = self.build_navpoints(refnodes)
|
||||||
level = max(item['level'] for item in self.refnodes)
|
level = max(item['level'] for item in self.refnodes)
|
||||||
level = min(level, self.config.epub_tocdepth)
|
level = min(level, self.config.epub_tocdepth)
|
||||||
with codecs.open(path.join(outdir, outname), 'w', 'utf-8') as f: # type: ignore
|
copy_asset_file(path.join(self.template_dir, 'toc.ncx_t'),
|
||||||
f.write(self.toc_template % self.toc_metadata(level, navpoints)) # type: ignore
|
path.join(outdir, outname),
|
||||||
|
self.toc_metadata(level, navpoints))
|
||||||
|
|
||||||
def build_epub(self, outdir, outname):
|
def build_epub(self, outdir, outname):
|
||||||
# type: (unicode, unicode) -> None
|
# type: (unicode, unicode) -> None
|
||||||
|
15
sphinx/templates/epub2/toc.ncx_t
Normal file
15
sphinx/templates/epub2/toc.ncx_t
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<ncx version="2005-1" xmlns="http://www.daisy.org/z3986/2005/ncx/">
|
||||||
|
<head>
|
||||||
|
<meta name="dtb:uid" content="{{ uid }}"/>
|
||||||
|
<meta name="dtb:depth" content="{{ level }}"/>
|
||||||
|
<meta name="dtb:totalPageCount" content="0"/>
|
||||||
|
<meta name="dtb:maxPageNumber" content="0"/>
|
||||||
|
</head>
|
||||||
|
<docTitle>
|
||||||
|
<text>{{ title }}</text>
|
||||||
|
</docTitle>
|
||||||
|
<navMap>
|
||||||
|
{{ navpoints }}
|
||||||
|
</navMap>
|
||||||
|
</ncx>
|
24
sphinx/templates/epub3/toc.ncx_t
Normal file
24
sphinx/templates/epub3/toc.ncx_t
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{%- macro navPoints(navlist) %}
|
||||||
|
{%- for nav in navlist %}
|
||||||
|
<navPoint id="{{ nav.navpoint }}" playOrder="{{ nav.playorder }}">
|
||||||
|
<navLabel>
|
||||||
|
<text>{{ nav.text }}</text>
|
||||||
|
</navLabel>
|
||||||
|
<content src="{{ nav.refuri }}" />{{ navPoints(nav.children)|indent(2, true) }}
|
||||||
|
</navPoint>
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endmacro -%}
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ncx version="2005-1" xmlns="http://www.daisy.org/z3986/2005/ncx/">
|
||||||
|
<head>
|
||||||
|
<meta name="dtb:uid" content="{{ uid }}"/>
|
||||||
|
<meta name="dtb:depth" content="{{ level }}"/>
|
||||||
|
<meta name="dtb:totalPageCount" content="0"/>
|
||||||
|
<meta name="dtb:maxPageNumber" content="0"/>
|
||||||
|
</head>
|
||||||
|
<docTitle>
|
||||||
|
<text>{{ title }}</text>
|
||||||
|
</docTitle>
|
||||||
|
<navMap>{{ navPoints(navpoints)|indent(4, true) }}
|
||||||
|
</navMap>
|
||||||
|
</ncx>
|
@ -139,3 +139,34 @@ def test_epub_cover(app):
|
|||||||
cover = opf.find("./idpf:metadata/idpf:meta[@name='cover']")
|
cover = opf.find("./idpf:metadata/idpf:meta[@name='cover']")
|
||||||
assert cover
|
assert cover
|
||||||
assert cover.get('content') == cover_image.get('id')
|
assert cover.get('content') == cover_image.get('id')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('epub', testroot='toctree')
|
||||||
|
def test_nested_toc(app):
|
||||||
|
app.build()
|
||||||
|
|
||||||
|
# toc.ncx
|
||||||
|
toc = EPUBElementTree.fromstring((app.outdir / 'toc.ncx').text())
|
||||||
|
assert toc.find("./ncx:docTitle/ncx:text").text == 'Python documentation'
|
||||||
|
|
||||||
|
# toc.ncx / navPoint
|
||||||
|
def navinfo(elem):
|
||||||
|
label = elem.find("./ncx:navLabel/ncx:text")
|
||||||
|
content = elem.find("./ncx:content")
|
||||||
|
return (elem.get('id'), elem.get('playOrder'),
|
||||||
|
content.get('src'), label.text)
|
||||||
|
|
||||||
|
navpoints = toc.findall("./ncx:navMap/ncx:navPoint")
|
||||||
|
assert len(navpoints) == 4
|
||||||
|
assert navinfo(navpoints[0]) == ('navPoint9', '1', 'index.xhtml',
|
||||||
|
"Welcome to Sphinx Tests's documentation!")
|
||||||
|
assert navpoints[0].findall("./ncx:navPoint") == []
|
||||||
|
|
||||||
|
# toc.ncx / nested navPoints
|
||||||
|
assert navinfo(navpoints[1]) == ('navPoint10', '2', 'foo.xhtml', 'foo')
|
||||||
|
navchildren = navpoints[1].findall("./ncx:navPoint")
|
||||||
|
assert len(navchildren) == 4
|
||||||
|
assert navinfo(navchildren[0]) == ('navPoint11', '2', 'foo.xhtml', 'foo')
|
||||||
|
assert navinfo(navchildren[1]) == ('navPoint12', '3', 'quux.xhtml', 'quux')
|
||||||
|
assert navinfo(navchildren[2]) == ('navPoint13', '4', 'foo.xhtml#foo-1', 'foo.1')
|
||||||
|
assert navinfo(navchildren[3]) == ('navPoint16', '6', 'foo.xhtml#foo-2', 'foo.2')
|
||||||
|
Loading…
Reference in New Issue
Block a user