Spaces:
Sleeping
Sleeping
File size: 5,549 Bytes
55d9355 ca18aa5 9c306e9 ca18aa5 6bc379e ca18aa5 55d9355 9c306e9 55d9355 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | """Notas de rodapé nativas, inclusive quando o documento já contém notas."""
from lxml import etree
from docx.oxml import OxmlElement, parse_xml
from docx.oxml.ns import qn
from docx.opc.constants import CONTENT_TYPE as CT, RELATIONSHIP_TYPE as RT
from docx.opc.packuri import PackURI
from docx.opc.part import Part, XmlPart
from docx.shared import Pt
from docx.text.paragraph import Paragraph
from copy import deepcopy
import re
from .public_text import public_text
def add_first_footnote(doc, pattern, text):
"""Attach a note immediately after the first body/table occurrence of a term."""
for element in doc.element.body.iter(qn('w:p')):
paragraph = Paragraph(element, doc._body)
if element.find('.//'+qn('m:oMath')) is not None:
display_text = ''.join(node.text or '' for node in element.iter()
if node.tag in (qn('w:t'),qn('m:t')))
if re.search(pattern,display_text):
# Word footnote references belong outside the math object.
# Keep the expression editable and place its marker after it.
return add_footnote(doc,paragraph,text)
match = re.search(pattern, paragraph.text)
if not match:
continue
offset = 0
for run in paragraph.runs:
end = offset + len(run.text)
if offset < match.end() <= end:
cut = match.end() - offset
tail = run.text[cut:]
run.text = run.text[:cut]
identifier = add_footnote(doc, paragraph, text)
marker = paragraph.runs[-1]._r
run._r.addnext(marker)
if tail:
remainder = OxmlElement('w:r')
if run._r.rPr is not None:
remainder.append(deepcopy(run._r.rPr))
content = OxmlElement('w:t')
content.text = tail
content.set(qn('xml:space'), 'preserve')
remainder.append(content)
marker.addnext(remainder)
return identifier
offset = end
return add_footnote(doc, paragraph, text)
return None
def order_footnotes(doc):
"""Keep IDs and stored note order aligned with their first body occurrence.
Notes can be attached retroactively to earlier terms. Align both orders so
Word and LibreOffice associate every visible number with the right text.
"""
try:
part = doc.part.part_related_by(RT.FOOTNOTES)
except KeyError:
return
root = parse_xml(part.blob)
notes = {n.get(qn('w:id')): n for n in root if int(n.get(qn('w:id'))) > 0}
refs = list(doc.element.body.iter(qn('w:footnoteReference')))
ordered_ids = list(dict.fromkeys(r.get(qn('w:id')) for r in refs))
ordered_ids += [key for key in notes if key not in ordered_ids]
mapping = {key: str(i+1) for i,key in enumerate(ordered_ids)}
for reference in refs:
reference.set(qn('w:id'),mapping[reference.get(qn('w:id'))])
for old_id in ordered_ids:
note = notes[old_id]
note.set(qn('w:id'),mapping[old_id])
root.append(note)
if isinstance(part,XmlPart):
part._element = root
else:
part._blob = etree.tostring(root,xml_declaration=True,encoding='UTF-8',standalone=True)
def add_footnote(doc, paragraph, text):
text = public_text(text)
try:
part = doc.part.part_related_by(RT.FOOTNOTES)
root = parse_xml(part.blob)
except KeyError:
root = OxmlElement('w:footnotes')
for identifier, kind in [(-1, 'separator'), (0, 'continuationSeparator')]:
note = OxmlElement('w:footnote')
note.set(qn('w:id'), str(identifier)); note.set(qn('w:type'), kind)
p = OxmlElement('w:p'); r = OxmlElement('w:r')
r.append(OxmlElement('w:'+kind)); p.append(r); note.append(p); root.append(note)
part = Part(PackURI('/word/footnotes.xml'), CT.WML_FOOTNOTES, b'', doc.part.package)
doc.part.relate_to(part, RT.FOOTNOTES)
identifier = max([0] + [int(n.get(qn('w:id'))) for n in root]) + 1
note = OxmlElement('w:footnote'); note.set(qn('w:id'), str(identifier))
p = OxmlElement('w:p'); props = OxmlElement('w:pPr')
spacing = OxmlElement('w:spacing'); spacing.set(qn('w:after'), '60')
props.append(spacing); p.append(props)
for marker, value in [('footnoteRef', None), ('t', ' '+text)]:
r = OxmlElement('w:r'); rp = OxmlElement('w:rPr')
font = OxmlElement('w:rFonts')
font.set(qn('w:ascii'), 'Arial'); font.set(qn('w:hAnsi'), 'Arial'); rp.append(font)
size = OxmlElement('w:sz'); size.set(qn('w:val'), '14'); rp.append(size)
if value is None:
vertical = OxmlElement('w:vertAlign'); vertical.set(qn('w:val'), 'superscript'); rp.append(vertical)
r.append(rp); element = OxmlElement('w:'+marker)
if value is not None:
element.text = value; element.set(qn('xml:space'), 'preserve')
r.append(element); p.append(r)
note.append(p); root.append(note)
if isinstance(part, XmlPart):
part._element = root
else:
part._blob = etree.tostring(root, xml_declaration=True, encoding='UTF-8', standalone=True)
run = paragraph.add_run(); run.font.superscript = True
run.font.size = Pt(7)
reference = OxmlElement('w:footnoteReference'); reference.set(qn('w:id'), str(identifier))
run._r.append(reference)
return identifier
|