I've searched everywhere but can't seem to find anything in the documentation or anywhere else. I've created my own custom theme, copypasting stuff from the Starter theme which ships with PyroCMS. In my navigation partial there is this twig directive:
{{ structure()
.linkAttributesDropdown({'data-toggle': 'dropdown'})
.listClass('nav navbar-nav navbar-right')
.childListClass('dropdown-menu')
.render()|raw }}
This works when using the Bootstrap framework. I am using Purecss.io and I want to assign different classes and assign classes to more elements. My navigation should look like this:
<ul class="pure-menu-list">
<li class="pure-menu-item pure-menu-selected">
<a href="http://local.dev" class="pure-menu-link" >Home</a>
</li>
<li class="pure-menu-item pure-menu-has-children pure-menu-allow-hover">
Item with children
<ul class="pure-menu-children">
<li class="pure-menu-item">
Child 1
</li>
<li class="pure-menu-item">
Child 2
</li>
</ul>
</li>
</ul>
I've tried the folling in my partial:
{{ structure()
.linkAttributesDropdown({'class': 'pure-menu-item pure-menu-has-children pure-menu-allow-hover'})
.listClass('pure-menu-list')
.elementClass('pure-menu-item')
.childListClass('pure-menu-children')
.render() }}
But that doesn't do the trick.
How would I accomplish this? Where can I find documentation for the used functions structure(), listClass() etc.?
Thanks in advance!
Unfortunately this portion of the system is still being developed but I can show you the macro and how to interact with it:
https://github.com/anomalylabs/pages-module/blob/master/resources/views/macro.twig
The chaining you are seeing is how you set the options so structure().fooBar(value) set's the foo_bar option to value in the options collection.
For elementClass you are probably looking for linkClass. Also don't forget to escape with |raw!
Looks like this will give you your desired markup:
{{ structure()
.currentClass('pure-menu-selected')
.dropdownClass('pure-menu-has-children pure-menu-allow-hover')
.linkAttributesDropdown({'class': 'pure-menu-item pure-menu-has-children pure-menu-allow-hover'})
.listClass('pure-menu-list')
.itemClass('pure-menu-item')
.linkClass('pure-menu-link')
.childListClass('pure-menu-children')
.render()|raw }}
Here's some information:
The very basic default looks like the following and will create an unordered list with all your existing pages. If you have set/toggled a page to be NOT enabled, then it will not show up.
{{ structure()|raw }}
Change the class of the list element
{{ structure().list_class('navigation')|raw }}
Change the list tag to something else than unordered list:
{{ structure().list_tag('dl')|raw }}
Change list element
{{ structure().link_tag('dt')|raw }}
Show children of only a specific page
{{ structure().root('/my-page')|raw }} or page-id {{ structure().root('9')|raw }}
Set class for the element with children
{{ structure().dropdown_class('has-children')|raw }}
Set a class to every li item:
{{ structure().item_class('has-children')|raw }}
Set a class to the link
{{ structure().link_class('my-class')|raw }}
Add a title attribute to the link
{{ structure().link_attributes({'title':'Title attribute'})|raw }}
Related
I have a component in my templating engine (that works well so far) that kind of needs to take an argument.
The component is a navigation on a website. In the CMS there can be many navigations (main, footer, side) but I can't get the logic for Mustache right.
My template `top.mustache':
<div id="wrap-top">
<div id="top">
{{> #navigation }}
{{ main }}
{{> /navigation }}
</div>
</div>
And then navigation.mustache is just:
<div class="nav">
{{ #navigation }}
</div>
In PHP I'm rendering it as follows:
$mustache->render("top", [
"navigation" => [
"main" => "HTML HERE"
]
];
The thing is that I don't want to create multiple tags like navigation_main or navigation_footer because the code is the same. The links may be different but that's handled in PHP where HTML is being generated.
The key is to not have to create mustache files for the names of the navigations. How do I put this all together? Just for the purpose of the question, let's say I do this:
{{ #navigation }}
{{ main }}
{{ /navigation }}
<-- some other html -->
{{ #navigation }}
{{ footer }}
{{ /navigation }}
And the result would be:
<div class="nav"><-- links from main here --></div>
<-- some other html -->
<div class="nav"><-- links from footer here --></div>
The reason is that the names of navigations can vary. In PHP I can prepare the array with all available options but how to use only one partial template?
Can anyone suggest a good way of setting the active class on the correct navbar menu item (e.g. in Bootstrap) based on what the current-handled fat-free route is?
The navbar menu in my main template looks like this:
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>Data
<li>About</li>
</ul>
I could put a check-if around each of these, something like:
<ul class="nav navbar-nav">
<li>{{ #route }}</li>
<li <check if="{{ #route == '/' }}"> class="active"</check>>Home</li>
<li <check if="{{ #route == '/data' }}"> class="active"</check>>Data
<li <check if="{{ #route == '/about' }}"> class="active"</check>>About</li>
</ul>
But that means both setting the #route variable in every route ($f3->set('route', $f3->get('PARAMS.0'))), and embedding the check and the route to compare it to in the template seems prone to error when making changes. I'd quite like to have the link appear active if the start of the route matches (e.g. still set the Data link as active if the route is /data/set/5/report), which would add to the complexity of the template.
I'm partially considering putting all the data for the menu inside an associative array in the code and generating the menu in the template, but I don't like the idea of taking the design of the menu out of the template and into the code.
Any ideas or discussion fully welcomed!
Well it depends partially on how you've defined your routes.
If your routes look like GET /#controller/#action, then the following should do the trick:
{~ $links=array(''=>'Home','data'=>'Data','about'=>'About') ~}
<ul>
<repeat group="#links" key="#ctrl" value="#label">
<li class="{{ #ctrl==##PARAMS.controller ? 'active' : '' }}">
{{ #label }}
</li>
</repeat>
</ul>
(Notice the double ## not to choke on homepage).
If your routes are defined one by one (GET /, GET /data, etc...), then you need to refine a bit the active state detection:
{~ $links=array('/'=>'Home','/data'=>'Data','/about'=>'About') ~}
<ul>
<repeat group="#links" key="#uri" value="#label">
<li class="{{ (#uri=='/' ? #PATH==#uri : strpos(#PATH,#uri)===0) ? 'active' : '' }}">
{{ #label }}
</li>
</repeat>
</ul>
If your routes are defined one by one and named appropriately (GET #home: /, GET #data: /data, GET #data_foo: /data/foo, etc...), then you can avoid hardcoding URIs inside templates:
{~ $links=array('home'=>'Home','data'=>'Data','about'=>'About') ~}
<ul>
<repeat group="#links" key="#name" value="#label">
<li class="{{ strpos(#ALIAS,#name)===0 ? 'active' : '' }}">
{{ #label }}
</li>
</repeat>
</ul>
Whichever method you choose, you may consider defining $links in a config file to improve maintainability.
I'm building a themed view in Drupal 8 using twig. I'd like to use twig filters on the row.content variable in the views-view-unformatted.html.twig template.
It seems that row.content is an array so twig's string manipulation doesn't work. However, it prints onto the page as a string (view is just a list of taxonomy terms).
What I'd like to do is slugify the output so taxonomy terms with spaces can have valid hrefs. See the replace filter in the code below.
<ul class="nav nav-tabs" role="tablist">
{% for row in rows %}
<li role="presentation" class="{{loop.first ? 'active' : ''}}">
{{row.content}}
</li>
{% endfor %}
</ul>
This will just output <a href="#">. Does anyone know how to access the raw text value that is output during twigs interpolation?
Thanks!
I ran into this myself it was difficult because kint and dump crashes on views.
there is a quick workaround to get to the bits though, put this under {% for row in rows %} in your twig views style template.
<ol>
{% for key, value in row.content %}
<li>{{ key }}</li>
{% endfor %}
</ol>
load the page with that & gives you the keys to see, I checked them each with the following dump command, just added underneath to test.
{{ dump(row.content['#row']) }}
The above dump showed all the goods in #row, where I dug in and found the field I wanted inside _entity (may be different for you), then I wanted to replace spaces with dash and force lowercase.
Everything past row.content['#row'] is likely different for you, you'll need to dig in the array a bit with the dump command mentioned above.
Below is the line that got me what I wanted.
{{ row.content['#row']._entity.title[0].value|replace(' ', '-')|lower }}
Below is twig template example.
For filename change viewname and block-3 to your setup.
views-view-unformatted--viewname--block-3.html.twig
{% for row in rows %}
{%
set row_classes = [
default_row_class ? 'views-row',
'something',
'kint-cant',
]
%}
{# My field value unformatted #}
<!-- {{ row.content['#row']._entity.title[0].value }} -->
<section{{ row.attributes.addClass(row_classes) }} id="{{ row.content['#row']._entity.title[0].value|replace(' ', '-')|lower }}">
{{ row.content }}
</section>
{% endfor %}
Im sure there are plenty of other ways to do this, but it worked for me as a quick solution to print out views fields in the style template, which is really useful.
In Handlebars, you can make conditionals, like:
{{#if isActive}}
<img src="star.gif" alt="Active">
{{/if}}
http://handlebarsjs.com/block_helpers.html
I've been trying for a while to do something like this in the PHP Mustache. But nowhere i can find anything allowing {{#something withvalue }}
Why not just use the {{#each }} to if something? If I want to Each over a list making lis, and I only want to wrap them in a ul when there are actually lis?
I would need an extra value that has prechecked the list, which I think is ugly.
{{#hasList }}
<ul>
{{# list }}
<li>{{ title }}</li>
{{/ list }}
</ul>
{{/hasList }}
There must be a way to handle this in Mustache, right?
I have a Team to which I would like to add players (objects of Player). I've set up the form "type" classes correctly. Here's the relevant part of my view:
{% for index, player in form.players %}
<div id="template" data-prototype="{{ form_widget(form.players.get('prototype')) | e }}">
<span class="title">{{ index }}</span>
{{ form_row(player.name) }}
</div>
{% endfor %}
My problem is that data-prototype attribute doesn't include the span tag; it only contains the output of {{ form_row(player.name) }}. Is there a way to include the whole content of div#template in the data-prototype attribute?
This was bugging me too. I customized a field type and even made simple form types with a reduced fieldset (for more complex objects), but it just didn't feel right. I've come up with a solution that should do the trick :)
First - I think your <div id="team" data-prototype="..."> should be outside your loop.
Next, your prototype is just a form view object, so if you pass it to a template you can render fields by hand and customize the output. Note: autoescape has no effect on included content, so use 'filter escape'.
<div id="playerFields" data-prototype="{% filter escape %}{% include 'AcmeTeamBundle:Team:prototypePlayer.html.twig' with {'form': form.players.get('prototype')} %}{% endfilter %}">
Then in your prototypePlayer.html.twig, just render each field as you normally would in a form view.
<div>
<span class="title">{{ form_label(form.name) }}</span>
{{ form_row(form.name) }}
<span class="age">{{ form_label(form.age) }}</span>
{{ form_row(form.age) }}
{# render whatever else you like from your Form/PlayerType class... #}
<div>
My template has a different data structure to your question, but it should help :)
Cheers,
Chris
Deprecation Warning:
As of Symfony 2.1, .get() is deprecated and the above will not work. Replace form.players.get('prototype') with form.players.vars.prototype to fix this in later versions of Symfony.