diff --git a/docxtpl/__init__.py b/docxtpl/__init__.py index 1c0e1df..0ec37f1 100644 --- a/docxtpl/__init__.py +++ b/docxtpl/__init__.py @@ -9,6 +9,6 @@ __version__ = "0.19.1" # flake8: noqa from .inline_image import InlineImage from .listing import Listing -from .richtext import RichText, R +from .richtext import RichText, R, RichTextParagraph, RP from .subdoc import Subdoc from .template import DocxTemplate diff --git a/docxtpl/richtext.py b/docxtpl/richtext.py index 75c3b1c..759eed0 100644 --- a/docxtpl/richtext.py +++ b/docxtpl/richtext.py @@ -119,5 +119,50 @@ class RichText(object): def __html__(self): return self.xml +class RichTextParagraph(object): + """class to generate Rich Text Paragraphs when using templates variables + + This is much faster than using Subdoc class, + but this only for texts OUTSIDE an existing paragraph. + """ + + def __init__(self, text=None, **text_prop): + self.xml = "" + if text: + self.add(text, **text_prop) + + def add( + self, + text, + parastyle=None, + ): + + # If a RichText is added + if not isinstance(text, RichText): + text = RichText(text) + + prop = "" + if parastyle: + prop += '' % parastyle + + xml = "" + if prop: + xml += "%s" % prop + xml += text.xml + xml += "" + self.xml += xml + + def __unicode__(self): + return self.xml + + def __str__(self): + return self.xml + + def __html__(self): + return self.xml + + + R = RichText +RP = RichTextParagraph diff --git a/docxtpl/template.py b/docxtpl/template.py index b246ca7..e9c9cc4 100644 --- a/docxtpl/template.py +++ b/docxtpl/template.py @@ -160,7 +160,7 @@ class DocxTemplate(object): flags=re.DOTALL, ) src_xml = re.sub( - r"({{r\s.*?}}|{%r\s.*?%})", + r"({{r.\s.*?}}|{%r.\s.*?%})", r'\1', src_xml, flags=re.DOTALL, @@ -173,7 +173,7 @@ class DocxTemplate(object): r"-%}(?:(?!]|{%|{{).)*?]*?>", "%}", src_xml, flags=re.DOTALL ) - for y in ["tr", "tc", "p", "r"]: + for y in ["tr", "tc", "p"]: # replace into xml code the row/paragraph/run containing # {%y xxx %} or {{y xxx}} template tag # by {% xxx %} or {{ xx }} without any surrounding tags : @@ -183,6 +183,18 @@ class DocxTemplate(object): % {"y": y} ) src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) + + for y in ["p", "r"]: + # replace into xml paragraph or run containing + # {%rp xxx %} or {{rp xxx}} template tag + # by {% xxx %} or {{ xx }} without any surrounding tags + # This allow for inline {rr }} and paragraph {rp }) styling + # This is mandatory to have jinja2 generating correct xml code + pat = ( + r"](?:(?!]).)*({%%|{{)r%(y)s ([^}%%]*(?:%%}|}})).*?" + % {"y": y} + ) + src_xml = re.sub(pat, r"\1 \2", src_xml, flags=re.DOTALL) for y in ["tr", "tc", "p"]: # same thing, but for {#y xxx #} (but not where y == 'r', since that diff --git a/tests/richtextparagraph.py b/tests/richtextparagraph.py new file mode 100644 index 0000000..e06bf47 --- /dev/null +++ b/tests/richtextparagraph.py @@ -0,0 +1,32 @@ +""" +Created : 2025-02-28 + +@author: Hannah Imrie +""" + +from docxtpl import DocxTemplate, RichText, RichTextParagraph + +tpl = DocxTemplate("templates/richtext_paragraph_tpl.docx") + +rtp = RichTextParagraph() +rt = RichText() + +rtp.add("The rich text paragraph function allows paragraph styles to be added to text",parastyle="myrichparastyle") + +rtp.add("This allows for the use of") +rtp.add("bullet\apoints.", parastyle="SquareBullet") + +rt.add("This works with ") +rt.add("Rich ", bold=True) +rt.add("Text ", italic=True) +rt.add("Strings", underline="single") +rt.add(" too.") + +rtp.add(rt, parastyle="SquareBullet") + +context = { + "example": rtp, +} + +tpl.render(context) +tpl.save("output/richtext_paragraph.docx") \ No newline at end of file diff --git a/tests/templates/richtext_paragraph_tpl.docx b/tests/templates/richtext_paragraph_tpl.docx new file mode 100644 index 0000000..738c502 Binary files /dev/null and b/tests/templates/richtext_paragraph_tpl.docx differ diff --git a/tests/templates/richtext_tpl.docx b/tests/templates/richtext_tpl.docx index bcf589e..be34203 100644 Binary files a/tests/templates/richtext_tpl.docx and b/tests/templates/richtext_tpl.docx differ