Skip to content

Commit a48a6a9

Browse files
author
Eric Lapouyade
committed
Merge branch 'refs/heads/ST-Imrie-master'
2 parents 6854250 + ebc770a commit a48a6a9

File tree

6 files changed

+102
-2
lines changed

6 files changed

+102
-2
lines changed

docxtpl/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
# flake8: noqa
1010
from .inline_image import InlineImage
1111
from .listing import Listing
12-
from .richtext import RichText, R
12+
from .richtext import RichText, R, RichTextParagraph, RP
1313
from .subdoc import Subdoc
1414
from .template import DocxTemplate

docxtpl/richtext.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,50 @@ def __str__(self):
128128
def __html__(self):
129129
return self.xml
130130

131+
class RichTextParagraph(object):
132+
"""class to generate Rich Text Paragraphs when using templates variables
133+
134+
This is much faster than using Subdoc class,
135+
but this only for texts OUTSIDE an existing paragraph.
136+
"""
137+
138+
def __init__(self, text=None, **text_prop):
139+
self.xml = ""
140+
if text:
141+
self.add(text, **text_prop)
142+
143+
def add(
144+
self,
145+
text,
146+
parastyle=None,
147+
):
148+
149+
# If a RichText is added
150+
if not isinstance(text, RichText):
151+
text = RichText(text)
152+
153+
prop = ""
154+
if parastyle:
155+
prop += '<w:pStyle w:val="%s"/>' % parastyle
156+
157+
xml = "<w:p>"
158+
if prop:
159+
xml += "<w:pPr>%s</w:pPr>" % prop
160+
xml += text.xml
161+
xml += "</w:p>"
162+
self.xml += xml
163+
164+
def __unicode__(self):
165+
return self.xml
166+
167+
def __str__(self):
168+
return self.xml
169+
170+
def __html__(self):
171+
return self.xml
172+
173+
174+
131175

132176
R = RichText
177+
RP = RichTextParagraph

docxtpl/template.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def cellbg(m):
161161
flags=re.DOTALL,
162162
)
163163
src_xml = re.sub(
164-
r"({{r\s.*?}}|{%r\s.*?%})",
164+
r"({{[rq]\s.*?}}|{%[rq].\s.*?%})",
165165
r'</w:t></w:r><w:r><w:t xml:space="preserve">\1</w:t></w:r><w:r><w:t xml:space="preserve">',
166166
src_xml,
167167
flags=re.DOTALL,
@@ -184,6 +184,18 @@ def cellbg(m):
184184
% {"y": y}
185185
)
186186
src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL)
187+
188+
# For paragraph level richtext
189+
# replace into xml paragraph containing
190+
# {%q xxx %} or {{q xxx}} template tag
191+
# by {% xxx %} or {{ xx }} without any surrounding <w:p> tags
192+
# This allow for inline {r <var> }} and paragraph {q <var> }) styling
193+
# This is mandatory to have jinja2 generating correct xml code
194+
pat = (
195+
r"<w:p[ >](?:(?!<w:p[ >]).)*({%%|{{)q ([^}%%]*(?:%%}|}})).*?</w:p>"
196+
197+
)
198+
src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL)
187199

188200
for y in ["tr", "tc", "p"]:
189201
# same thing, but for {#y xxx #} (but not where y == 'r', since that

tests/richtextparagraph.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Created : 2025-02-28
3+
4+
@author: Hannah Imrie
5+
"""
6+
7+
from docxtpl import DocxTemplate, RichText, RichTextParagraph
8+
9+
tpl = DocxTemplate("templates/richtext_paragraph_tpl.docx")
10+
11+
rtp = RichTextParagraph()
12+
rt = RichText()
13+
14+
rtp.add("The rich text paragraph function allows paragraph styles to be added to text",parastyle="myrichparastyle")
15+
rtp.add("Any built in paragraph style can be used", parastyle="IntenseQuote")
16+
rtp.add("or you can add your own, unlocking all style options", parastyle="createdStyle")
17+
rtp.add("To use, just create a style in your template word doc with the formatting you want and call it in the code.", parastyle="normal")
18+
19+
rtp.add("This allows for the use of")
20+
rtp.add("custom bullet\apoints", parastyle="SquareBullet")
21+
rtp.add("Numbered Bullet Points", parastyle="BasicNumbered")
22+
rtp.add("and Alpha Bullet Points.", parastyle="alphaBracketNumbering")
23+
rtp.add("You can", parastyle="normal")
24+
rtp.add("set the", parastyle="centerAlign")
25+
rtp.add("text alignment", parastyle="rightAlign")
26+
rtp.add("as well as the spacing between lines of text. Like this for example, this text has very tight spacing between the lines.\aIt also has no space between paragraphs of the same style.", parastyle="TightLineSpacing")
27+
rtp.add("Unlike this one, which has extra large spacing between lines for when you want to space things out a bit or just write a little less.", parastyle="WideLineSpacing")
28+
rtp.add("You can also set the background colour of a line.", parastyle="LineShadingGreen")
29+
30+
rt.add("This works with ")
31+
rt.add("Rich ", bold=True)
32+
rt.add("Text ", italic=True)
33+
rt.add("Strings", underline="single")
34+
rt.add(" too.")
35+
36+
rtp.add(rt, parastyle="SquareBullet")
37+
38+
context = {
39+
"example": rtp,
40+
}
41+
42+
tpl.render(context)
43+
tpl.save("output/richtext_paragraph.docx")
20 KB
Binary file not shown.

tests/templates/richtext_tpl.docx

2.62 KB
Binary file not shown.

0 commit comments

Comments
 (0)