mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Move TOC creation into its own module
This commit is contained in:
parent
8bc65df29a
commit
ba0639c681
@ -25,9 +25,8 @@ from calibre.ebooks.docx.tables import Tables
|
|||||||
from calibre.ebooks.docx.footnotes import Footnotes
|
from calibre.ebooks.docx.footnotes import Footnotes
|
||||||
from calibre.ebooks.docx.cleanup import cleanup_markup
|
from calibre.ebooks.docx.cleanup import cleanup_markup
|
||||||
from calibre.ebooks.docx.theme import Theme
|
from calibre.ebooks.docx.theme import Theme
|
||||||
|
from calibre.ebooks.docx.toc import create_toc
|
||||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
from calibre.ebooks.metadata.toc import TOC
|
|
||||||
from calibre.ebooks.oeb.polish.toc import elem_to_toc_text
|
|
||||||
from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1
|
from calibre.utils.localization import canonicalize_lang, lang_as_iso639_1
|
||||||
|
|
||||||
class Text:
|
class Text:
|
||||||
@ -267,48 +266,8 @@ class Convert(object):
|
|||||||
|
|
||||||
self.styles.resolve_numbering(numbering)
|
self.styles.resolve_numbering(numbering)
|
||||||
|
|
||||||
def create_toc(self):
|
|
||||||
' Create a TOC from headings in the document '
|
|
||||||
root = self.body
|
|
||||||
headings = ('h1', 'h2', 'h3')
|
|
||||||
tocroot = TOC()
|
|
||||||
xpaths = [XPath('//%s' % x) for x in headings]
|
|
||||||
level_prev = {i+1:None for i in xrange(len(xpaths))}
|
|
||||||
level_prev[0] = tocroot
|
|
||||||
level_item_map = {i+1:frozenset(xp(root)) for i, xp in enumerate(xpaths)}
|
|
||||||
item_level_map = {e:i for i, elems in level_item_map.iteritems() for e in elems}
|
|
||||||
|
|
||||||
self.idcount = 0
|
|
||||||
|
|
||||||
def ensure_id(elem):
|
|
||||||
ans = elem.get('id', None)
|
|
||||||
if not ans:
|
|
||||||
self.idcount += 1
|
|
||||||
ans = 'toc_id_%d' % self.idcount
|
|
||||||
elem.set('id', ans)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
for item in descendants(root, *headings):
|
|
||||||
lvl = plvl = item_level_map.get(item, None)
|
|
||||||
if lvl is None:
|
|
||||||
continue
|
|
||||||
parent = None
|
|
||||||
while parent is None:
|
|
||||||
plvl -= 1
|
|
||||||
parent = level_prev[plvl]
|
|
||||||
lvl = plvl + 1
|
|
||||||
elem_id = ensure_id(item)
|
|
||||||
text = elem_to_toc_text(item)
|
|
||||||
toc = parent.add_item('index.html', elem_id, text)
|
|
||||||
level_prev[lvl] = toc
|
|
||||||
for i in xrange(lvl+1, len(xpaths)+1):
|
|
||||||
level_prev[i] = None
|
|
||||||
|
|
||||||
if len(tuple(tocroot.flat())) > 1:
|
|
||||||
return tocroot
|
|
||||||
|
|
||||||
def write(self):
|
def write(self):
|
||||||
toc = self.create_toc()
|
toc = create_toc(self.body)
|
||||||
raw = html.tostring(self.html, encoding='utf-8', doctype='<!DOCTYPE html>')
|
raw = html.tostring(self.html, encoding='utf-8', doctype='<!DOCTYPE html>')
|
||||||
with open(os.path.join(self.dest_dir, 'index.html'), 'wb') as f:
|
with open(os.path.join(self.dest_dir, 'index.html'), 'wb') as f:
|
||||||
f.write(raw)
|
f.write(raw)
|
||||||
|
60
src/calibre/ebooks/docx/toc.py
Normal file
60
src/calibre/ebooks/docx/toc.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
from calibre.ebooks.docx.names import XPath, descendants
|
||||||
|
from calibre.ebooks.metadata.toc import TOC
|
||||||
|
from calibre.ebooks.oeb.polish.toc import elem_to_toc_text
|
||||||
|
|
||||||
|
class Count(object):
|
||||||
|
|
||||||
|
__slots__ = ('val',)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.val = 0
|
||||||
|
|
||||||
|
def create_toc(body):
|
||||||
|
' Create a TOC from headings in the document '
|
||||||
|
headings = ('h1', 'h2', 'h3')
|
||||||
|
tocroot = TOC()
|
||||||
|
xpaths = [XPath('//%s' % x) for x in headings]
|
||||||
|
level_prev = {i+1:None for i in xrange(len(xpaths))}
|
||||||
|
level_prev[0] = tocroot
|
||||||
|
level_item_map = {i+1:frozenset(xp(body)) for i, xp in enumerate(xpaths)}
|
||||||
|
item_level_map = {e:i for i, elems in level_item_map.iteritems() for e in elems}
|
||||||
|
|
||||||
|
idcount = Count()
|
||||||
|
|
||||||
|
def ensure_id(elem):
|
||||||
|
ans = elem.get('id', None)
|
||||||
|
if not ans:
|
||||||
|
idcount.val += 1
|
||||||
|
ans = 'toc_id_%d' % idcount.val
|
||||||
|
elem.set('id', ans)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
for item in descendants(body, *headings):
|
||||||
|
lvl = plvl = item_level_map.get(item, None)
|
||||||
|
if lvl is None:
|
||||||
|
continue
|
||||||
|
parent = None
|
||||||
|
while parent is None:
|
||||||
|
plvl -= 1
|
||||||
|
parent = level_prev[plvl]
|
||||||
|
lvl = plvl + 1
|
||||||
|
elem_id = ensure_id(item)
|
||||||
|
text = elem_to_toc_text(item)
|
||||||
|
toc = parent.add_item('index.html', elem_id, text)
|
||||||
|
level_prev[lvl] = toc
|
||||||
|
for i in xrange(lvl+1, len(xpaths)+1):
|
||||||
|
level_prev[i] = None
|
||||||
|
|
||||||
|
if len(tuple(tocroot.flat())) > 1:
|
||||||
|
return tocroot
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user