Parsing and using list item content via Twig - templates

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!

Related

Replace function inside value not working

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

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.

How to indent Django templates properly

I work in SublimeText 3. When writing Django templates I have a mixture of html and functions.
I like to indent my code so that block, if and other such statements are indented. For example:
Manual formatting
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
{% endblock %}
However, when I run any autoformatter HTML-CSS-JS-Prettify it ignores these brackets and treats them as text:
After formatting
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
{% endblock %}
Although plugins like Djaneiro give great tag highlighting, I haven't been able to find a way to get SublimeText to treat these as tags.
Has anyone had any luck?
This is a late answer, but I would like to mention a Django template formatter that I've created myself: DjHTML. You can install it using pip install djhtml.
Let's say template.html contains the following:
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
<script>
$(function() {
console.log("Password changed!");
});
</script>
{% endblock %}
Then running djhtml template.html will give the following output:
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
<script>
$(function() {
console.log("Password changed!");
});
</script>
{% endblock %}
It's easiest to use DjHTML as a pre-commit hook, so that templates will be automatically indented when you run git commit. Instructions on how to configure pre-commit can be found in the README.
There isn't one for sublime text as far as I can tell. I have no source I can quote on this, but I have basically searched nothing came up.
This discussion is by any means old, but active. I found this really old ticket about formatting standards for Django and it has been updated 9 Months ago to basically say they are "in favour of standards" and the proposed formatting for templates would be:
<ul>
{% for x in y %}
<li>{{ x }}</li>
{% endfor %}
</ul>
They also made a place happen that holds information about formatting guidelines in Django.
You might find this discussion interesting as well. It's old too, but it highlights the confusion about formatting in Django and the DIY solutions people came up with to cope.

Adding an if statement to django-cms template tag

I'm probably missing something very obvious but can't see anything in the documentation. I have a carousel with a and each will hold an image. However I've added 6 but I want to add an if statement so if an Image has not been added you don't see a blank space, where there is no content inside the .
Here is what i've tried so far:
{% if "Carousel 1" %}
<li>
{% placeholder "Carousel 1" %}
</li>
{% endif %}
Attempt 2:
{% placeholder "Carousel 1" as cara1 %}
{% if cara1 %}
<li>
{{ cara1 }}
</li>
{% endif %}
Not sure if there is something differnt i need to be doing for the django-cms template tags?
Any help would be much appreciated. Docs here - http://docs.django-cms.org/en/latest/advanced/templatetags.html#placeholder
Not to be rude, but your approach is way, way off :)
Placeholders hold Content Plugins. Content Plugins are responsible for how they render their contents.
My advice would be to create or find a carousel content type plugin. This plugin will hold multiple images or "CarouselImage" model instances that you can iterate over, and also specify a template with which to render itself.
In this template resides the conditional statement you're wanting to check for. Placeholders are just that - places held for content plugins.

Breaking data into multiple display columns with Django

Overlap in terminology makes search for answers difficult for this one.
I'm looking for advice on the best way to implement a multiple-column display of my QuerySet that fills each column top to bottom over X columns. Meaning that the number of items in each column equals the QuerySet count divided by X (number of columns).
Using Offset doesn't work for this because I would like my data to grow into 4 columns without updating the offset manually. CSS floats work visually, but leave the data out of order.
Something like that should work for you, pass the number of columns as columns to the template:
{% for item in items %}
{% if forloop.first %}<div style="float:left;">{% endif %}
{{ item }}
{% if forloop.counter|divisibleby:columns %}
</div><div style="float:left">
{% endif %}
{% if forloop.last %}</div>{% endif %}
{% endfor %}
<div style="clear:both;"></div>
It seems like lazerscience's answer is on the right track - but I think the OP wants the data to alphabetically sort the data down the column and then start back at the top of the next column. Using divisibleby: works to break the line after 'X' items, but I think it'll take a more complex template to do what the OP wants.
Not sure if it's possible, but in the view could you: Get item count, divide by 'columns' and used that # in Divisibleby to break into the next DIV column (the visual flow will be CSS)
As Lazers's example is now you're constructing Rows and then breaking it into columns, leaving the sort order across and then down.
Sorry if I missed something.
-K
You'd better go and use a jQuery plugin to make some columns from a list.
Columnizer works very well for me
Here are some django template filter that split a list into multiple sub-lists:
list partition template filters at djangosnippets.org
You could use these in a django template to split a long list into multiple columns as follows:
{% load list_tags %}
<h2>Some List</h2>
{% for sub_list in full_list|rows:"3" %}
<ul>
{% for item in sub_list %}
<li>
{{item.name}}
</li>
{% endfor %}
</ul>
{% endfor %}
I included the template filters in my project in a file called list_tags.py. Adjust the {% load %} tag as necessary.