Reputation: 32094
I have a code-formatting issue. I need to output a sequence of strings and there should be no spaces between the printed strings (since I actually print words by segments, highlighting typos), but I am a bit confused how to indent the code to make it readable. The problem is that when I ident the code, the line-breaks and spaces become part of the output.
<b>{% for sub in segment.details %}{% if sub.is_marked %}<u>{{sub.text}}</u
>{% else %}{{sub.text}}{% endif %}{% empty %}{{ segment.text }}{% endfor %}</b>
Obviously, {% spaceless %}
tag is useless here, since it only strips spaces between >
and <
. I could but I would not like to wrap other segments in separate spans. In XSLT one usually uses <xsl:text/>
for the purpose, what is the best practice for the case in Django templates?
UPD: posted my final solution as a separate answer below.
Upvotes: 2
Views: 716
Reputation: 32094
For completeness, I decided to post my final solution:
The code of the strip_spacenodes
tag:
def _strip__space__text_nodes(nodelist):
for node in nodelist:
if isinstance(node, template.TextNode):
if not node.s.strip():
node.s = ''
else:
for list_ in node.child_nodelists:
_strip__space__text_nodes(getattr(node, list_, ()))
class StripSpaceNodes(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
_strip__space__text_nodes(nodelist)
def render(self, context):
return self.nodelist.render(context)
@register.tag
def strip_spacenodes(parser, token):
nodelist = parser.parse(('endstrip_spacenodes',))
parser.delete_first_token()
return StripSpaceNodes(nodelist)
The usage:
{% strip_spacenodes %}
{% for segment in segments %}
{% if segment.is_marked %}
{##}<b>{##}
{% for sub in segment.details %}
{% if sub.is_marked %}
{##}<u>{{sub.text}}</u>{##}
{% else %}
{{sub.text}}
{% endif %}
{% empty %}
{{ segment.text }}
{% endfor %}
{##}</b> {##}
{% else %}
{{ segment.text }}
{% endif %}
{% endfor %}
{% endstrip_spacenodes %}
Mind the {##}
blocks that break a single TextNode with linefeed and spaces before an HTML tag into three nodes: space only TextNode, CommentNode and TextNode with HTML tag. TextNodes that contain spaces only are stripped.
Upvotes: 0
Reputation: 118538
You could make a tag that strips as you need - lately all of my django projects have a templatetags directory for stuff like this. It pays for itself quite quickly in time / readability IMO. My most common tags are shared across projects.
Recent versions have made simple tag creation very easy which is why it's now in my workflow (though that's unrelated to this one...).
@register.tag
def remove_whitespace(parser, token):
nodelist = parser.parse(('endremove_whitespace',))
parser.delete_first_token()
return RemoveSpaces(nodelist)
class RemoveSpaces(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
return ''.join(output.split()) # modify behavior if desired
{% load mytags %}
{% remove_whitespace %}
<b>All whitespace stripped</b>
{% endremove_whitespace %}
Upvotes: 3
Reputation: 15073
You could always put the newlines inside template comment tags:
<b>{% for sub in segment.details %}{#
#}{% if sub.is_marked %}{#
#}<u>{{sub.text}}</u>{#
#}{% else %}{{sub.text}}{#
#}{% endif %}{#
#}{% empty %}{{ segment.text }}{#
#}{% endfor %}</b>
Upvotes: 3