contentpanel - template formatting improved
This commit is contained in:
@@ -35,7 +35,7 @@ def validate_template(template: Path) -> None:
|
||||
_placeholders(minidom.parseString(archive.read('word/document.xml')))
|
||||
|
||||
|
||||
def _set_text(paragraph, text):
|
||||
def _set_text(paragraph, text):
|
||||
if any(ord(char) < 32 and char not in '\t\n\r' for char in text):
|
||||
raise TemplateError('Text enthält ungültige Steuerzeichen.')
|
||||
nodes = paragraph.getElementsByTagNameNS(W, 't')
|
||||
@@ -44,22 +44,49 @@ def _set_text(paragraph, text):
|
||||
node.removeChild(node.firstChild)
|
||||
document, anchor = paragraph.ownerDocument, nodes[0]
|
||||
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||
for part in re.split(r'(\n|\t)', text):
|
||||
for part in re.split(r'(\n|\t)', text):
|
||||
if part in ('\n', '\t'):
|
||||
node = document.createElementNS(W, 'w:br' if part == '\n' else 'w:tab')
|
||||
else:
|
||||
node = document.createElementNS(W, 'w:t')
|
||||
node.setAttribute('xml:space', 'preserve')
|
||||
node.appendChild(document.createTextNode(part))
|
||||
anchor.parentNode.insertBefore(node, anchor)
|
||||
anchor.parentNode.removeChild(anchor)
|
||||
# Preserve verse/signature lines without stretching them to the full width.
|
||||
if '\n' in text:
|
||||
for alignment in paragraph.getElementsByTagNameNS(W, 'jc'):
|
||||
alignment.setAttributeNS(W, 'w:val', 'left')
|
||||
|
||||
|
||||
def fill_template(template: Path, output: Path, title: str, date_label: str, paragraphs: list[str]) -> None:
|
||||
anchor.parentNode.insertBefore(node, anchor)
|
||||
anchor.parentNode.removeChild(anchor)
|
||||
if '\n' in text:
|
||||
paragraph.getElementsByTagNameNS(W, 'jc')[0].setAttributeNS(W, 'w:val', 'left')
|
||||
|
||||
|
||||
def _items(text):
|
||||
lines = [line.strip() for line in text.replace('\r\n', '\n').replace('\r', '\n').split('\n') if line.strip()]
|
||||
bullets = [line[1:].lstrip() if line.startswith('•') and line[1:].strip() else None for line in lines]
|
||||
if not any(bullets):
|
||||
return [(text, None)]
|
||||
return [(bullet, i + 1 < len(lines) and bullets[i + 1] is not None) if bullet else (line, None)
|
||||
for i, (line, bullet) in enumerate(zip(lines, bullets))]
|
||||
|
||||
|
||||
def _format_bullet(paragraph, compact):
|
||||
properties = paragraph.getElementsByTagNameNS(W, 'pPr')[0]
|
||||
anchor = properties.getElementsByTagNameNS(W, 'jc')[0]
|
||||
document = paragraph.ownerDocument
|
||||
tabs = document.createElementNS(W, 'w:tabs')
|
||||
tab = document.createElementNS(W, 'w:tab')
|
||||
tab.setAttributeNS(W, 'w:val', 'left')
|
||||
tab.setAttributeNS(W, 'w:pos', '480')
|
||||
tabs.appendChild(tab)
|
||||
properties.insertBefore(tabs, anchor)
|
||||
if compact:
|
||||
spacing = document.createElementNS(W, 'w:spacing')
|
||||
spacing.setAttributeNS(W, 'w:after', '0')
|
||||
properties.insertBefore(spacing, anchor)
|
||||
indent = document.createElementNS(W, 'w:ind')
|
||||
indent.setAttributeNS(W, 'w:left', '480')
|
||||
indent.setAttributeNS(W, 'w:hanging', '360')
|
||||
properties.insertBefore(indent, anchor)
|
||||
|
||||
|
||||
def fill_template(template: Path, output: Path, title: str, date_label: str, paragraphs: list[str]) -> None:
|
||||
paragraphs = [p.strip() for p in paragraphs if p.strip()]
|
||||
if not title.strip() or not date_label.strip() or not paragraphs:
|
||||
raise TemplateError('Titel, Datum und Inhalt dürfen nicht leer sein.')
|
||||
@@ -69,16 +96,19 @@ def fill_template(template: Path, output: Path, title: str, date_label: str, par
|
||||
_set_text(placeholders[TITLE_TOKEN], title.strip())
|
||||
_set_text(placeholders[DATE_TOKEN], date_label.strip())
|
||||
body = placeholders[BODY_TOKEN]
|
||||
used = {p.getAttributeNS(W14, 'paraId') for p in document.getElementsByTagNameNS(W, 'p')}
|
||||
index = 1
|
||||
for text in paragraphs:
|
||||
paragraph = body.cloneNode(deep=True)
|
||||
while f'{index:08X}' in used:
|
||||
index += 1
|
||||
paragraph.setAttributeNS(W14, 'w14:paraId', f'{index:08X}')
|
||||
used.add(f'{index:08X}')
|
||||
_set_text(paragraph, text)
|
||||
body.parentNode.insertBefore(paragraph, body)
|
||||
used = {p.getAttributeNS(W14, 'paraId') for p in document.getElementsByTagNameNS(W, 'p')}
|
||||
index = 1
|
||||
for text in paragraphs:
|
||||
for value, compact in _items(text):
|
||||
paragraph = body.cloneNode(deep=True)
|
||||
while f'{index:08X}' in used:
|
||||
index += 1
|
||||
paragraph.setAttributeNS(W14, 'w14:paraId', f'{index:08X}')
|
||||
used.add(f'{index:08X}')
|
||||
_set_text(paragraph, f'•\t{value}' if compact is not None else value)
|
||||
if compact is not None:
|
||||
_format_bullet(paragraph, compact)
|
||||
body.parentNode.insertBefore(paragraph, body)
|
||||
body.parentNode.removeChild(body)
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zipfile.ZipFile(output, 'w') as target:
|
||||
|
||||
Reference in New Issue
Block a user