Replace function inside value not working - replace

Maybe I'm doing it wrong (tried several ways to achieve my goal) or overlooking something here.
What I'd like to achieve is this:
When I use the Live-search function, I get categories containing the search keyword (like: Paint -> Paint buckets, Paint brushes, Paint colors etc.) which works like a charm. The one thing I need is to style the searched keyword in the presented categories like:
Paint bucket,
Paint brushes,
Color paint
This is the code I have at the moment:
{% if (products.length + categories.length + pages.length) == 0 %}
<div id="Pi56dYpB" class="undefined"> No results for:
<b>{{ query }}</b>...
</div>
{% endif %}
{% if categories.length > 0 %}
<div class="categories">
{% for category in categories %}
{% if loop.index < 7 %}
<a class="p-0" href="{{ category.url }}" style="all:inherit;">
<h3 id="bvwiyjEN" class="undefined">{{ category.name|replace({{ query }}: "<strong>"{{ query }}"<strong>"})|raw }}</h3>
</a>
{% endif %}
{% endfor %}
{% endif %}
Unfortunately this isn't working. I did check if the {{ query }} value is accessible with this simple line of code:
<h3 id="bvwiyjEN" class="undefined">{{ category.name }} - {{ query }}</h3>
No problems found here.
Did I use the wrong syntax in my code maybe? Any help would be appreciated!

replace({{ query }}) is the wrong syntax - replace(query) should work, as you don't want to echo the variable query here

As Nico Haase pointed out already, {{ ... }} is used to output variables, this translate to something like <?php echo $foo; ?> and can't/shouldn't be used inside statements
Furthermore, the filter replace expects an array of keys to replace with the values.
You would need to change your code to the following:
{% for category in categories %}
{{ category|replace({ (query): '<strong>'~query~'</strong>',})|raw }}
{% endfor %}
demo
Some notes:
The filter replace uses the PHP function strtr in the background. This mean the output will be case-sensitive. If you don't want this, I'd advice you to follow through here
Wrapping the key with parantheses is mandatory. This will force twig to evaluate/interpolate the value of the key - demo

Related

How to do regex search and then show the regex match as an output in jinja2?

So i have this jinja2 code
{% for vul3 in vul.ports_data %}
{% if vul3.vulnerabilities.vulners and vul3.vulnerabilities.vulners | trim | length %}
<td><label class="badge badge-success">{{ vul3.vulnerabilities.vulners }}</label></td>
{% endif %}
{% endfor %}
And it shows this output,
cpe:/a:igor_sysoev:nginx:1.20.0: NGINX:CVE-2021-23017 6.8 https://vulners.com/nginx/NGINX:CVE-2021-23017 9A14990B-D52A-56B6-966C-6F35C8B8EB9D 6.8 https://vulners.com/githubexploit/9A14990B-D52A-56B6-966C-6F35C8B8EB9D *EXPLOIT* 1337DAY-ID-36300 6.8 https://vulners.com/zdt/1337DAY-ID-36300 *EXPLOIT* PACKETSTORM:162830 0.0 https://vulners.com/packetstorm/PACKETSTORM:162830 *EXPLOIT*
I want to use this regex CVE-(?:(?:18|19|20|21)[0-9]{2})-[0-9]{5} to show only the CVEs in this string. Like below
CVE-2021-23017
CVE-2021-23017
Thanks!
The regex is fine and I'd suggest adding this in your view code, or even as an accessor, perhaps:
{% for vul3 in vul.ports_data %}
{% with vulns as vul3.vulnerabilities.vulners|trim|length %}
{% for cve in vulns.regex_list %}
<td>...
Or whatever you want to call it. I don't believe there is a built-in Jinja regex method that returns the list you're looking for, so you'll either want to add a custom filter or just add it in your view/model code which I'd suggest.

Parsing and using list item content via Twig

I am experimenting with using Grav to create my next website. One of the things I would be able to do is to build a unordered list using data provided in Grav frontmatter from the Grav page that uses the template. Here is how I am trying to do this
---
sectionone:
listitems: "['Benefit 1','Benefit 2','Benefit 3']"
---
and then in the template somehow do the following
{% block featurelist %}
<ul>
{% set items = {{page.header.sectionone.consumers.benefits|json_decode}} %}
{% for item in {{}} %}
<li>{{item}}</li>
{% endfor %}
</ul>
{% endblock %}
However, Twig does not like this and reports back an error along the lines of
Twig_Error_Syntax
A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "punctuation" of value "{".
with the offending line being my {% set items = ... } statement. I am clearly doing something wrong here but I am a Twig newbie so I fail to see what that might be.
{% block featurelist %}
<ul>
{% set items = page.header.sectionone.consumers.benefits|json_decode %}
{% for item in items %}
<li>{{item}}</li>
{% endfor %}
</ul>
{% endblock %}
I figured this out eventually. Grav documentation is by and large very good. However, the documentation on page headers/frontmatter appears to be somewhat incomplete. There is no full description of the entire syntax that is understood by the frontmatter processor. In order to define an array in front matter all you need to do is the following
---
sectionone:
benefits:
- 'Benefit 1'
- 'Benefit 2'
- ...
---
In essence the standard markdown syntax for an unordered list. Grav's twig processor appears to convert this to a PHP array - no parsing required!

How to mark string for translation in jinja2 using trans blocks

I am using django and jinja2 and have something like this in one of my html pages
<p><strong>Q. {{ _("What products will you accept?") }}</strong></p>
<p class="style3"><strong>A: </strong>{% trans myurl=request.url('start') %}A list of qualifying devices is available once you start your trade-in estimate. <a href= {{myurl}}>Click here</a> to learn what your old device is worth.</p>{% endtrans %}
When I run django-admin.py makemessages, "What products will you accept?" is the only string that gets processed. I thought that wrapping a string with the {% trans %} block also marks that string or is this a wrong statement?
What is the best technique to mark that second string (it's tricky because of the request.url variable)
I've tried {{ _("A list of qualifying devices is available once you start your trade-in estimate. <a href= {{ request.url('start') }}>Click here</a> to learn what your old device is worth.")|safe }} but then the link doesn't work properly.
To translate a block like that you need to use the {% blocktrans %} template tag,
{% blocktrans with myurl=request.url('start') %}
A list of qualifying devices is available once you start your trade-in estimate. <a href= {{myurl}}>Click here</a> to learn what your old device is worth.</p>
{% endblocktrans %}
However, I'm not sure you can call a function like that anywhere in a template like you are attempting.
Consider instead passing myurl in as a template variable, and then using smaller chunks of text. This increases reuse of the translations - especially for small common blocks like "Click here".
{% blocktrans %}
"A list of qualifying devices is available once you start your trade-in estimate."
{% endblocktrans %}
<a href= {{myurl}}>{% trans "Click here" %}</a>
{% trans "to learn what your old device is worth." %}
Also, when using HTML and template tags, try and keep them correctly nested. For example, in your code you would have:
<p>... {% blocktrans %}... </p>{% endblocktrans %}
Instead try to nest them like so:
<p>... {% blocktrans %}... {% endblocktrans %}</p>
This is especially useful for IDEs that can auto indent and fold content and helps readability.

Django templates - Formatting strings

I've these variables:
#Int
user.id
#Float (e.g. X.YYYY)
profile.rating
I need these formatted like so (the ` is delimiter):
`profile.rating`
I've tried numerous ways to format them, but none worked. For example, concatenating them: ""|add:profile.rating|add:"" gave me nothing (literally, nothing).
I suspect that this is because add: is numbers-first, but converting the numbers into string with either slugify or stringformat:"" gave me, again, nothing.
How do I do this?
Do note: I need to do this with filters since the result will be passed as a parameter to an include.
Update:
Basically, I'm building a sort of modular include. It include looks like this:
<section>
...
{% if custom_section %}
<section id="{{ custom_section_id }}">
{{ custom_section }}
</section>
{% endif %}
...
</section>
which means that I can't just directly include the values in a parameter, I need the markup that will go inside the nested section.
I managed to solve this issue with this piece of markup:
{% with "<a href="\"/user/" as link_start %}
{% with profile.rating|stringformat:".1f" as rating %}
{% with user.id|slugify as id %}
{% with link_start|add:id|add:"/\">" as link %}
{% with link|add:rating|add:"/5</a>" as data %}
{% include "XX" with custom_data:data|safe %}
{% endwith %} a couple of times
Key here is the |stringformat:".1f" and the user.id|slugify since without them, djangos worthless templating language defaults on the belief all values are numerical, and thus crap comes out.
Of note is the |safe as well, as without it the language escapes the value.
Do note: I need to do this with filters since the result will be
passed as a parameter to an include.
You can pass them directly to include, as it will take context correctly.
{% include user.id %}

Can I specify a multiline context variable/parameter when {% include %}ing a template?

I know that it is possible to set context variables when including a Django template from another template using
{% include "default_table.html" with table_header=table_header1 table_data=table_data1 %}
or
{% with "My data" as table_data %}
{% include 'default_table.html' %}
{% endwith %}
My issue with this is that both approaches don't let me define multiline variables (unless they are based on a previous multiline variable of course).
My specific usecase is this
<!-- widget.html -->
<div class="box">
<div class="title">{{ title }}</div>
<div class="title">{{ body }}</div>
</div>
and I'd like to be able to set a longer text for the body context variable. This will make is possible for me to reuse common widget HTML in various places. Can this be done?
I've been searching a bit on http://djangosnippets.org for an über {% with ... %} template tag, but haven't found any so far.
This Django snippet kinda solves my issue: http://djangosnippets.org/snippets/1860/ But I'd love to be able to set context variables instead of defining {% localblock step_ready_js %}{% endlocalblock %} in my widget HTML.