Create arrays and objects with fluids f:variable - typo3

Is it possible to create an array or an object with f:variable in TYPO3 9.x?
The example below does not work, because it treat the object as an string.
<f:variable name="person">{firstname:'Max', lastname:'Mustermann'}</f:variable>
Update: This example is working:
<f:variable name="person" value="{firstname:'Max', lastname:'Mustermann'}" />
Why is the tag syntax treaten differently?
What's interesting, is the fact that you can 'build' arrays in fluid and pass them as arguments to a partial.
Example:
<f:render partial="Components/ImageGallery" section="ImageGallery" arguments="{
imageGallery: {
0:{imageurl:'https://www.placehold.it/640x480',imagealt:'First Image', },
1:{imageurl:'https://www.placehold.it/640x480',imagealt:'Second Alt'}
}
}" />
It would be great, if it is possible in fluid to build this object with f:variable. Yes i know, i could assign this object, but that is not my intention.

Here you have an example partial from https://github.com/Startpiloten/startpilot
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:if condition="{file}">
<f:if condition="{breakpoints}">
<f:else>
<f:variable name="breakpoints" value="{settings.breakpoints}" />
</f:else>
</f:if>
<f:link.typolink parameter="{file.link}" class="picturelink">
<picture>
<f:for each="{breakpoints}" as="breakpoint" iteration="i_breakpoints">
<f:if condition="{i_breakpoints.isLast}">
<f:else>
<source srcset="{f:uri.image(image: file, maxWidth: breakpoint.maxWidth, cropVariant: breakpoint.cropVariant)}" media="({breakpoint.media}: {breakpoint.size}px)">
</f:else>
<f:then>
<source srcset="{f:uri.image(image: file, maxWidth: breakpoint.maxWidth, cropVariant: breakpoint.cropVariant)}" media="({breakpoint.media}: {breakpoint.size}px)">
<img class="img-fluid" src="{f:uri.image(image: file, maxWidth: breakpoint.maxWidth, cropVariant: breakpoint.cropVariant)}" alt="{file.alternative}" title="{file.title}">
</f:then>
</f:if>
</f:for>
</picture>
</f:link.typolink>
</f:if>
<f:comment>
<!---Render Image with custom sizes from TS settings--->
<f:render partial="ImageRender" arguments="{file:file, breakpoints:settings.breakpoints}" />
<!---Render Image with custom sizes -- START --->
<f:variable name="breakpoints" value="{
0:{media:'max-width', size:375, maxWidth:375, cropVariant:'mobile'},
1:{media:'max-width', size:480, maxWidth:480, cropVariant:'mobile'},
2:{media:'max-width', size:767, maxWidth:767, cropVariant:'tablet'},
3:{media:'max-width', size:991, maxWidth:991, cropVariant:'tablet'},
4:{media:'max-width', size:1279, maxWidth:1279, cropVariant:'default'},
5:{media:'max-width', size:1479, maxWidth:1479, cropVariant:'default'},
6:{media:'min-width', size:1480, maxWidth:2000, cropVariant:'default'}
}"/>
<f:render partial="ImageRender" arguments="{file:image, breakpoints:breakpoints}" />
<!---Render Image with custom sizes -- END --->
<!---Render Image with default sizes -- START --->
<f:render partial="ImageRender" arguments="{file:image}" />
</f:comment>
</html>

Related

Is there an alternative for <flux:field.file /> in Flux/Fluid TYPO3

<flux:field.file /> is deprecated in the latest version of TYPO3/Fluid.
Is there an alternative? How can I upload my videos in the backend right now?
You can try that:
Configuration:
<flux:field.inline.fal name="settings.bgImage" label="LLL:EXT(...)" required="0" />
Preview:
<v:content.resources.fal field="settings.bgImage" as="images" record="{record}">
<f:for each="{images}" as="image">
<f:if condition="{image}">
<f:image src="{image.id}" treatIdAsReference="1" maxWidth="100" />
</f:if>
</f:for></v:content.resources.fal>
Main:
<f:if condition='{settings.bgImage}'>
{v:content.resources.fal(field: 'settings.bgImage') -> v:iterator.first() -> v:variable.set(name: 'bgImage')}
<f:image treatIdAsReference="true" src="{bgImage.id}" title="{bgImage.title}" alt="{bgImage.alternative}" width="100c" /></f:if>

EXT:Form - Get layout field from content object data

I'm trying to get the layout field of the content object data inside an ext:form content element, to add a css class if a specific layout has been chosen. But nether the content object data is added to the fluid template (typo3/sysext/form/Classes/Controller/FormFrontendController.php:73) nor the frame container from fluid_styled_content is rendered for this element.
My layout field is configured like this:
TCEFORM.tt_content {
layout {
types.form_formframework {
addItems {
200 = Blue Form
}
removeItems = 1,2,3
}
}
}
I have also tried to add a new layout field to the form configuration itself:
TYPO3:
CMS:
Form:
########### FORMEDITOR CONFIGURATION ###########
prototypes:
standard:
########### DEFAULT FORM ELEMENT DEFINITIONS ###########
formElementsDefinition:
Form:
formEditor:
editors:
9000:
identifier: 'layout'
group: select
templateName: 'Inspector-SingleSelectEditor'
label: 'Layout'
propertyPath: 'properties.layout'
selectOptions:
0:
value:
label: Normal
1:
value: form--blue
label: Blau
This works great in the backend but is leading to an The options "properties" were not allowed error in the frontend as properties for the form element are hardcoded in typo3/sysext/form/Classes/Domain/Model/FormDefinition.php:382.
Any ideas how to add a layout selection here? Best would be on the content element, as this would allow me to use the same form configuration with different layouts instead off making a duplicate form configuration which only distinguish in the layout.
The content object data is available in the Generic-Template from fluid_styled_content. Here you can check if the Ctype is 'form_formframework' and wrapping the form with your css class.
<f:if condition="{content}">
<f:then>
{content -> f:format.raw()}
</f:then>
<f:else>
<f:if condition="{data.CType} == 'form_formframework'">
<f:then>
<div class="{data.layout}">
<f:cObject typoscriptObjectPath="tt_content.{data.CType}.20" data="{data}" table="tt_content"/>
</div>
</f:then>
<f:else>
<f:cObject typoscriptObjectPath="tt_content.{data.CType}.20" data="{data}" table="tt_content"/>
</f:else>
</f:if>
</f:else>
</f:if>
We can add the fluid template layout like this({f:if(condition:'{data.layout}',then:'blue')}), in to default fluid_style_content/Resource/Private/Layouts/default.html (we Can override the fluid template in our site template) - without thinking for override the finisher and Flexform values of form:
<f:if condition="{data.CType} == 'form_formframework'">
<f:then>
<section id="c{data.uid}" class="form-section {f:if(condition:'{data.layout}',then:'blue')}">
<f:if condition="{data._LOCALIZED_UID}">
<a id="c{data._LOCALIZED_UID}"></a>
</f:if>
<f:render section="Before" optional="true">
<f:render partial="DropIn/Before/All" arguments="{_all}" />
</f:render>
<f:render section="Header" optional="true">
<f:render partial="Header/All" arguments="{_all}" />
</f:render>
<f:render section="Main" optional="true" />
<f:render section="Footer" optional="true">
<f:render partial="Footer/All" arguments="{_all}" />
</f:render>
<f:render section="After" optional="true">
<f:render partial="DropIn/After/All" arguments="{_all}" />
</f:render>
</section>
</f:then>
<f:else>
<div id="c{data.uid}" class="frame frame-{data.frame_class} frame-type-{data.CType} frame-layout-{data.layout}{f:if(condition: data.space_before_class, then: ' frame-space-before-{data.space_before_class}')}{f:if(condition: data.space_after_class, then: ' frame-space-after-{data.space_after_class}')}">
<f:if condition="{data._LOCALIZED_UID}">
<a id="c{data._LOCALIZED_UID}"></a>
</f:if>
<f:render section="Before" optional="true">
<f:render partial="DropIn/Before/All" arguments="{_all}" />
</f:render>
<f:render section="Header" optional="true">
<f:render partial="Header/All" arguments="{_all}" />
</f:render>
<f:render section="Main" optional="true" />
<f:render section="Footer" optional="true">
<f:render partial="Footer/All" arguments="{_all}" />
</f:render>
<f:render section="After" optional="true">
<f:render partial="DropIn/After/All" arguments="{_all}" />
</f:render>
</div>
</f:else>
</f:if>
I hope it helpful to all!

TYPO3 9.5.0 - pageUid of f:link.page not reading t3://page?uid=80

I have a TYPO3 9.5.0LTS and use the bootstrap package theme. It seems to be all working ... except ... when I add a link (internal or external) to a carousel item ... nothing gets rendered. The other elements come out fine.
I looked in the CalltoAction.html ... and found out that pageUid of f:link.page is not reading t3://page?uid=80.
When I {records} ... I get link => 't3://page?uid=80' (16 chars)
And when I test in CalltoAction.html:
<p>{item.data.link}</p>
<f:if condition="{item.data.link}">
<f:link.page pageUid="1" class="carousel-item-button btn btn-primary" additionalAttributes="{draggable:'false'}">
<f:if condition="{item.data.button_text}">
<f:then>
<span>{item.data.button_text}</span>
</f:then>
<f:else>
<span><f:translate key="readmore" extensionName="bootstrap_package" /></span>
</f:else>
</f:if>
</f:link.page>
</f:if>
<f:if condition="{item.data.link}">
<f:link.page pageUid="{item.data.link}" class="carousel-item-button btn btn-primary" additionalAttributes="{draggable:'false'}">
<f:if condition="{item.data.button_text}">
<f:then>
<span>{item.data.button_text}</span>
</f:then>
<f:else>
<span><f:translate key="readmore" extensionName="bootstrap_package" /></span>
</f:else>
</f:if>
</f:link.page>
</f:if>
I get the following result in the FE:
<p>t3://page?uid=80</p>
<a draggable="false" class="carousel-item-button btn btn-primary" href="/"><span>Read more</span></a>
<span>Read more</span>
So pageUid of f:link.page not reading t3://page?uid=80
How can I solve this?
the f:link.page-VH expects an integer (uid) in the parameter pageUid.
t3://page?uid=80 by way is no integer but a string. A special string which can be handled by the f:link.typo3link-VH

Split detail view in seperate content areas

How can I split the detail view in seperate content areas?
I configured 2 content areas as backend layouts:
backend_layout {
colCount = 1
rowCount = 2
rows {
1 {
columns {
1 {
name = News-Head
colPos = 0
}
}
}
2 {
columns {
1 {
name = News without Head
colPos = 22
}
}
}
}
}
and 1 News layout for the single view with head only:
tx_news.templateLayouts {
20 = Detail (Head only)
}
after that I inserted the 2 plugins in his associated content areas and select the news layout 20 on a single plugin.
Now I inserted a switch inside the Fluid template detail.html
<f:if condition="{settings.templateLayout} == 20">
<f:then>
<h1>
<f:if condition="{newsItem.alternativeTitle}">
<f:then>
<n:titleTag>
<f:format.htmlentitiesDecode>{newsItem.alternativeTitle}</f:format.htmlentitiesDecode>
</n:titleTag>
</f:then>
<f:else>
<n:titleTag>
<f:format.htmlentitiesDecode>{newsItem.title}</f:format.htmlentitiesDecode>
</n:titleTag>
</f:else>
</f:if>
</h1>
</f:then>
<f:else>
<div class="news news-single">
<div class="article" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="news-col">
<n:renderMedia news="{newsItem}" imgClass="img-responsive" videoClass="video-wrapper" audioClass="audio-wrapper">
<f:render partial="Detail/MediaContainer" arguments="{media: newsItem.media, settings:settings}" />
</n:renderMedia>
</div>
<div class="news-col">
<f:format.html>{newsItem.bodytext}</f:format.html>
</div>
</div>
</div>
</f:else>
</f:if>
But only the output of else branch works. Why?
Thanks in advance for help.
It was my fault! I totally forgot to pass-through my page variable content_news_single from my main fluid template to my partial.
TS setting:
page.10 = FLUIDTEMPLATE
page.10 {
# ....
variables{
content_main < styles.content.get
content_news_single < styles.content.get
content_news_single.select.where = colPos = 22
}
}
And here I forgot the definition to pass-through the variable content_news_single
<div class="page">
<f:render partial="header" arguments="{content_border:content_border}" />
<f:render partial="body" arguments="{content_main:content_main,content_news_single:content_news_single}" />
<f:render partial="footer" />
</div>
Also I never inserted {newsItem.title}
<f:if condition="{settings.templateLayout} == 20">
<f:then>
<n:format.nothing>
<n:excludeDisplayedNews newsItem="{newsItem}" />
<f:if condition="{newsItem.alternativeTitle}">
<f:then>
<n:titleTag>
<f:format.htmlentitiesDecode>{newsItem.alternativeTitle}</f:format.htmlentitiesDecode>
</n:titleTag>
</f:then>
<f:else>
<n:titleTag>
<f:format.htmlentitiesDecode>{newsItem.title}</f:format.htmlentitiesDecode>
</n:titleTag>
</f:else>
</f:if>
<f:render partial="Detail/Opengraph" arguments="{newsItem: newsItem, settings:settings}" />
</n:format.nothing>
<h1>
{newsItem.title}
</h1>
</f:then>
<f:else>
<div class="news news-single">
<div class="article" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="news-col">
<n:renderMedia news="{newsItem}" imgClass="img-responsive" videoClass="video-wrapper" audioClass="audio-wrapper">
<f:render partial="Detail/MediaContainer" arguments="{media: newsItem.media, settings:settings}" />
</n:renderMedia>
</div>
<div class="news-col">
<f:format.html>{newsItem.bodytext}</f:format.html>
</div>
</div>
</div>
</f:else>
</f:if>

Add to the second position of a Fluid array

Currently I have this code that wraps every 2 items with <li></li>
<f:for each="{modules}" as="module" iteration="loop">
<f:cycle values="{0: 1, 1: 0}" as="header">
<li>
</f:cycle>
...stuff here...
<f:cycle values="{0: 0, 1: 1}" as="footer">
</li>
</f:cycle>
</f:for>
Lets say {modules} = [A,B,C,D] and output is something like this:
<li>AB</li>
<li>CD</li>
What I need to do is add custom html to the second position. So my desired output is:
<li>AX</li>
<li>BC</li>
<li>D</li>
How can I do this?
To your updated question I would say, you may want to solve this issue with your own Helper class before adding modules to the View through the Controller.
It is however possible to build it simple in the template:
Here is the documentation about the for ViewHelper.
For simplicity I would do the following:
<f:for each="{modules}" as="module" iteration="loop">
<f:if condition="{loop.isFirst}">
<f:then>
<li>
{module}
##extra_code##
</li>
</f:then>
<f:else>
<f:if condition="{loop.isEven}">
<li>
</f:if>
...stuff here...
<f:if condition="{loop.isOdd} || {loop.isLast}">
</li>
</f:if>
</f:else>
</f:if>
</f:for>
Note: The first element will be "odd" because isOdd takes the current interation (based on "cycle"), which starts with 1.
For the first element there is your own block. You can take the first module and write your own code. It will run only once.
From the second element to the last it will use the 2 element in one li logic. Here is only one interesting thing, that we need take isOdd OR isLast to always close the last li, even if you have an even number of elements.
You can do this like below.
<f:for each="{modules}" as="module" iteration="iteration">
<f:if condition="{iteration.isFirst}">
<f:then>
<li>
</f:then>
<f:else>
<f:if condition="{iteration.index}%2">
<f:then></f:then>
<f:else><li></f:else>
</f:if>
</f:else>
</f:if>
<!--
Here Your Content
-->
<f:if condition="{iteration.isLast}">
<f:then>
</li>
</f:then>
<f:else>
<f:if condition="{iteration.cycle}%2">
<f:then></f:then>
<f:else></li></f:else>
</f:if>
</f:else>
</f:if>
</f:for>