mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
DOCX Input: When the document has a Table of Contents created using the Word Table of Contents tool, keep a reference to it in the metadata. This is useful when converting to old style MOBI and you want to precisely control placement of the ToC. Fixes #1556983 [ENHANCEMENT: FRONT TOC FOR MOBI](https://bugs.launchpad.net/calibre/+bug/1556983)
This commit is contained in:
parent
9dbe10d2a1
commit
a93ca1eaa0
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import sys, os, re, math, errno
|
||||
import sys, os, re, math, errno, uuid
|
||||
from collections import OrderedDict, defaultdict
|
||||
|
||||
from lxml import html
|
||||
@ -105,6 +105,7 @@ class Convert(object):
|
||||
self.anchor_map = {}
|
||||
self.link_map = defaultdict(list)
|
||||
self.link_source_map = {}
|
||||
self.toc_anchor = None
|
||||
self.block_runs = []
|
||||
paras = []
|
||||
|
||||
@ -364,9 +365,13 @@ class Convert(object):
|
||||
opf.create_spine(['index.html'])
|
||||
if self.cover_image is not None:
|
||||
opf.guide.set_cover(self.cover_image)
|
||||
def process_guide(E, guide):
|
||||
if self.toc_anchor is not None:
|
||||
guide.append(E.reference(
|
||||
href='index.html#' + self.toc_anchor, title=_('Table of Contents'), type='toc'))
|
||||
toc_file = os.path.join(self.dest_dir, 'toc.ncx')
|
||||
with open(os.path.join(self.dest_dir, 'metadata.opf'), 'wb') as of, open(toc_file, 'wb') as ncx:
|
||||
opf.render(of, ncx, 'toc.ncx')
|
||||
opf.render(of, ncx, 'toc.ncx', process_guide=process_guide)
|
||||
if os.path.getsize(toc_file) == 0:
|
||||
os.remove(toc_file)
|
||||
return os.path.join(self.dest_dir, 'metadata.opf')
|
||||
@ -413,7 +418,7 @@ class Convert(object):
|
||||
except AttributeError:
|
||||
break
|
||||
|
||||
for x in self.namespace.descendants(p, 'w:r', 'w:bookmarkStart', 'w:hyperlink'):
|
||||
for x in self.namespace.descendants(p, 'w:r', 'w:bookmarkStart', 'w:hyperlink', 'w:instrText'):
|
||||
if p_parent(x) is not p:
|
||||
continue
|
||||
if x.tag.endswith('}r'):
|
||||
@ -445,6 +450,16 @@ class Convert(object):
|
||||
self.anchor_map[a] = current_anchor
|
||||
elif x.tag.endswith('}hyperlink'):
|
||||
current_hyperlink = x
|
||||
elif x.tag.endswith('}instrText') and x.text and x.text.strip().startswith('TOC '):
|
||||
old_anchor = current_anchor
|
||||
anchor = str(uuid.uuid4())
|
||||
self.anchor_map[anchor] = current_anchor = generate_anchor('toc', frozenset(self.anchor_map.itervalues()))
|
||||
self.toc_anchor = current_anchor
|
||||
if old_anchor is not None:
|
||||
# The previous anchor was not applied to any element
|
||||
for a, t in tuple(self.anchor_map.iteritems()):
|
||||
if t == old_anchor:
|
||||
self.anchor_map[a] = current_anchor
|
||||
|
||||
m = re.match(r'heading\s+(\d+)$', style.style_name or '', re.IGNORECASE)
|
||||
if m is not None:
|
||||
|
@ -1396,7 +1396,7 @@ class OPFCreator(Metadata):
|
||||
self.guide.set_basedir(self.base_path)
|
||||
|
||||
def render(self, opf_stream=sys.stdout, ncx_stream=None,
|
||||
ncx_manifest_entry=None, encoding=None):
|
||||
ncx_manifest_entry=None, encoding=None, process_guide=None):
|
||||
if encoding is None:
|
||||
encoding = 'utf-8'
|
||||
toc = getattr(self, 'toc', None)
|
||||
@ -1519,6 +1519,8 @@ class OPFCreator(Metadata):
|
||||
if ref.title:
|
||||
item.set('title', ref.title)
|
||||
guide.append(item)
|
||||
if process_guide is not None:
|
||||
process_guide(E, guide)
|
||||
|
||||
serialize_user_metadata(metadata, self.get_all_user_metadata(False))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user