mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
DOCX Output: Start work on lists
This commit is contained in:
parent
63a2f3c21e
commit
627981f349
@ -13,6 +13,7 @@ from calibre.ebooks.docx.writer.styles import StylesManager, FloatSpec
|
||||
from calibre.ebooks.docx.writer.images import ImagesManager
|
||||
from calibre.ebooks.docx.writer.fonts import FontsManager
|
||||
from calibre.ebooks.docx.writer.tables import Table
|
||||
from calibre.ebooks.docx.writer.lists import ListsManager
|
||||
from calibre.ebooks.oeb.stylizer import Stylizer as Sz, Style as St
|
||||
from calibre.ebooks.oeb.base import XPath, barename
|
||||
|
||||
@ -96,8 +97,9 @@ class TextRun(object):
|
||||
|
||||
class Block(object):
|
||||
|
||||
def __init__(self, namespace, styles_manager, html_block, style, is_table_cell=False, float_spec=None):
|
||||
def __init__(self, namespace, styles_manager, html_block, style, is_table_cell=False, float_spec=None, is_list_item=False):
|
||||
self.namespace = namespace
|
||||
self.list_tag = (html_block, style) if is_list_item else None
|
||||
self.parent_items = None
|
||||
self.html_block = html_block
|
||||
self.float_spec = float_spec
|
||||
@ -116,6 +118,8 @@ class Block(object):
|
||||
return
|
||||
if len(self.html_block) > 0 and self.html_block[0] is next_block.html_block:
|
||||
self.skipped = True
|
||||
if self.list_tag is not None:
|
||||
next_block.list_tag = self.list_tag
|
||||
|
||||
def add_text(self, text, style, ignore_leading_whitespace=False, html_parent=None, is_parent_style=False):
|
||||
ts = self.styles_manager.create_text_style(style, is_parent_style=is_parent_style)
|
||||
@ -201,9 +205,11 @@ class Blocks(object):
|
||||
self.current_block.parent_items = self.items
|
||||
self.current_block = None
|
||||
|
||||
def start_new_block(self, html_block, style, is_table_cell=False, float_spec=None):
|
||||
def start_new_block(self, html_block, style, is_table_cell=False, float_spec=None, is_list_item=False):
|
||||
self.end_current_block()
|
||||
self.current_block = Block(self.namespace, self.styles_manager, html_block, style, is_table_cell=is_table_cell, float_spec=float_spec)
|
||||
self.current_block = Block(
|
||||
self.namespace, self.styles_manager, html_block, style,
|
||||
is_table_cell=is_table_cell, float_spec=float_spec, is_list_item=is_list_item)
|
||||
self.open_html_blocks.add(html_block)
|
||||
return self.current_block
|
||||
|
||||
@ -286,6 +292,7 @@ class Convert(object):
|
||||
|
||||
self.styles_manager = StylesManager(self.docx.namespace)
|
||||
self.images_manager = ImagesManager(self.oeb, self.docx.document_relationships)
|
||||
self.lists_manager = ListsManager(self.docx)
|
||||
self.fonts_manager = FontsManager(self.docx.namespace, self.oeb, self.opts)
|
||||
self.blocks = Blocks(self.docx.namespace, self.styles_manager)
|
||||
|
||||
@ -305,6 +312,7 @@ class Convert(object):
|
||||
for pos, block in reversed(remove_blocks):
|
||||
self.blocks.delete_block_at(pos)
|
||||
|
||||
self.lists_manager.finalize(all_blocks)
|
||||
self.styles_manager.finalize(all_blocks)
|
||||
self.write()
|
||||
|
||||
@ -338,8 +346,7 @@ class Convert(object):
|
||||
else:
|
||||
self.add_inline_tag(tagname, html_tag, tag_style, stylizer)
|
||||
elif display == 'list-item':
|
||||
# TODO: Implement this
|
||||
self.add_block_tag(tagname, html_tag, tag_style, stylizer)
|
||||
self.add_block_tag(tagname, html_tag, tag_style, stylizer, is_list_item=True)
|
||||
elif display.startswith('table') or display == 'inline-table':
|
||||
if display == 'table-cell':
|
||||
self.blocks.start_new_cell(html_tag, tag_style)
|
||||
@ -374,8 +381,8 @@ class Convert(object):
|
||||
block = self.blocks.current_or_new_block(html_tag.getparent(), stylizer.style(html_tag.getparent()))
|
||||
block.add_text(html_tag.tail, stylizer.style(html_tag.getparent()), is_parent_style=True)
|
||||
|
||||
def add_block_tag(self, tagname, html_tag, tag_style, stylizer, is_table_cell=False, float_spec=None):
|
||||
block = self.blocks.start_new_block(html_tag, tag_style, is_table_cell=is_table_cell, float_spec=float_spec)
|
||||
def add_block_tag(self, tagname, html_tag, tag_style, stylizer, is_table_cell=False, float_spec=None, is_list_item=False):
|
||||
block = self.blocks.start_new_block(html_tag, tag_style, is_table_cell=is_table_cell, float_spec=float_spec, is_list_item=is_list_item)
|
||||
if tagname == 'img':
|
||||
self.images_manager.add_image(html_tag, block, stylizer)
|
||||
else:
|
||||
|
86
src/calibre/ebooks/docx/writer/lists.py
Normal file
86
src/calibre/ebooks/docx/writer/lists.py
Normal file
@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
LIST_STYLES = frozenset(
|
||||
'disc circle square decimal decimal-leading-zero lower-roman upper-roman'
|
||||
' lower-greek lower-alpha lower-latin upper-alpha upper-latin hiragana hebrew'
|
||||
' katakana-iroha cjk-ideographic'.split())
|
||||
|
||||
STYLE_MAP = {
|
||||
'disc': 'bullet',
|
||||
'circle': 'o',
|
||||
'square': '\uf0a7',
|
||||
'decimal': 'decimal',
|
||||
'decimal-leading-zero': 'decimalZero',
|
||||
'lower-roman': 'lowerRoman',
|
||||
'upper-roman': 'upperRoman',
|
||||
'lower-alpha': 'lowerLetter',
|
||||
'lower-latin': 'lowerLetter',
|
||||
'upper-alpha': 'upperLetter',
|
||||
'upper-latin': 'upperLetter',
|
||||
'hiragana': 'aiueo',
|
||||
'hebrew': 'hebrew1',
|
||||
'katakana-iroha': 'iroha',
|
||||
'cjk-ideographic': 'chineseCounting',
|
||||
}
|
||||
|
||||
|
||||
def find_list_containers(list_tag, tag_style):
|
||||
node = list_tag
|
||||
stylizer = tag_style.stylizer
|
||||
ans = []
|
||||
while True:
|
||||
parent = node.getparent()
|
||||
if parent is None or parent is node:
|
||||
break
|
||||
node = parent
|
||||
style = stylizer.style(node)
|
||||
lst = (style._style.get('list-style-type', None) or '').lower()
|
||||
if lst in LIST_STYLES:
|
||||
ans.append(node)
|
||||
return ans
|
||||
|
||||
class NumberingDefinition(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
class Level(object):
|
||||
|
||||
def __init__(self, list_type, container, items, ilvl=0):
|
||||
self.ilvl = ilvl
|
||||
try:
|
||||
self.start = int(container.get('start'))
|
||||
except Exception:
|
||||
self.start = 1
|
||||
if list_type in {'disc', 'circle', 'square'}:
|
||||
self.num_fmt = 'bullet'
|
||||
self.lvl_text = '%1' if list_type == 'disc' else STYLE_MAP['list_type']
|
||||
else:
|
||||
self.lvl_text = '%1.'
|
||||
self.num_fmt = STYLE_MAP.get(list_type, 'decimal')
|
||||
|
||||
class ListManager(object):
|
||||
|
||||
def __init__(self, docx):
|
||||
self.namespace = docx.namespace
|
||||
|
||||
def finalize(self, all_blocks):
|
||||
lists = defaultdict(list)
|
||||
for block in all_blocks:
|
||||
if block.list_tag is not None:
|
||||
list_tag, tag_style = block.list_tag
|
||||
list_type = (tag_style['list-style-type'] or '').lower()
|
||||
if list_type not in LIST_STYLES:
|
||||
continue
|
||||
container_tags = find_list_containers(list_tag, tag_style)
|
||||
if not container_tags:
|
||||
continue
|
||||
lists[(tuple(container_tags), list_type)].append((list_tag, tag_style))
|
Loading…
x
Reference in New Issue
Block a user