How to print something alternatively with fluid in typo3? - fluid

I'm learning to handle typo3. I understand that what I'm using here is Fluid to call the variable from my backend
I have this template
<f:layout name="Default" />
<f:section name="Main">
<div class="container">
<f:cObject typoscriptObjectPath="lib.dynamicContent" data="{colPos: '21'}" />
</div>
</f:section>
And this is the template? I'm printing my content element with.
<html data-namespace-typo3-fluid="true"
xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers">
<div class="row">
<div class="col-7 ">
<div class="screen">
<div class="screenshot">
<f:for each="{screenshots}" as="screenshot">
<f:image style="opacity: 1;" image="{screenshot}" />
</f:for>
</div>
<a href="#" target="_blank">
<img src="typo3conf/ext/hebotek_website/Resources/Public/Images/screen.png" width="100%">
</a>
</div>
</div>
<div class="col-5">
<f:for each="{logos}" as="logo">
<f:image style="opacity: 1;" image="{logo}" />
</f:for>
<div class="project_desc">
<h3>
{data.header}
</h3>
<f:format.html>{data.bodytext}</f:format.html>
</div>
</div>
</div>
</html>
This will print two columns, the first one with a picture and the second one with a header and a text.
I want to print one time the image at the left and the next time the image at the right and the next at the left again. How do I alternate the html here? Is this possible with fluid or I must take a different approach?
Something like:
if(index % 2 == 0)
{
print left
}
else
{
print right
}
In any of this two templates I have an array in order to do this.
Thanks!

Unfortunately, there is no real alternate functionality in fluid.
You could use your approach with a condition:
<f:if condition="{index % 2 == 0}">
<f:then>
print left
</f:then>
<f:else>
print right
</f:else>
</f:if>
Fluid also provides a way to render partials in separate files, to reduce the amount of markup in your template:
<f:render partial="path/to/your/partial/left">
But a better approach will probably be to use css to alternate your layout.
For example with flexbox:
.row:nth-child(even) .col-6.image {
order: 1;
}
.row:nth-child(even) .col-6.text {
order: 2;
}
.row:nth-child(odd) .col-6.image {
order: 2;
}
.row:nth-child(odd) .col-6.text {
order: 1;
}
This way, you can also use a media query, to keep your top-bottom order for smaller screens, so your images or your text are not next to each other.

Related

Show as Html on vuejs

i have json file for translate ( en.json ) and this line :
{
"cancel order": "Hi, How can i <b> Cancel </b> ?",
}
<div class="d-flex align-items-center justify-content-center align-content-center mb-4">
<span class="description col-sm-11 col-md-7 col-lg-10">
{{ $t('cancel order') }}
</span>
</div>
now my result is " Hi, How can i Cancel "
The problem is that the html code does not apply like this code and the tags are displayed exactly without being applied.
You can use the v-html directive to rander raw html.
const htmlcontent = '<h1>Hello</h1>'
<span v-html="htmlcontent">
</span>
https://vuejs.org/guide/essentials/template-syntax.html#raw-html
use this :
<div v-html="$t('cancel order')"></div>
One observation : Using camelCase in property names consider as a best practice. Hence, use cancel order instead of cancel order.
To render your translation as an HTML message and not a static string. You can use v-html.
Template :
<span class="description col-sm-11 col-md-7 col-lg-10" v-html="$t('cancelOrder')"></span>

Vue check in nested v-for if a record doesn't exist

I am trying to build a table where rows are items (first v-for), columns are locations (second v-for), cells are item_locations (third -v-for).
If for a certain location the item is present (hence an item_location object) I want to print yes, else I want to print No.
<div v-for="item in items" :key="item.id>
{{item.name}}
<div v-for="location in locations" :key="location.id">
<div v-for="item_location in location.item_locations" :key="item_location.id">
</div>
</div>
</div>
By adding this in the third loop:
<p v-if="item_location.item_id == item.id">Yes</p>
I it correctly prints yes for combination of item/location for which there is an item_location.
What I am unable to do is to print No only for the combinations of item/location for which an item_location object does not exist. To further clarify, item_locations is a joining table.
A little confused on what your asking but Im going to suggest this
Your nested v-for must use the property declared from its parent like so
<div class="table-cell" v-for="location in locations" :key="location.id">
<div v-for="item_location in location.item_locations" :key="item_location.id">
<div v-if="item_location.location_id == location.id ">Yes</div>
<div v-else>No</div>
</div>
</div>
so the nested v-for would be location.item_locations and if your only checking for one condition you can just do a v-else.
I solved this way:
<div v-for="item in items" :key="item.id>
{{item.name}}
<div v-for="location in locations" :key="location.id">
<div>{{filterLocation(item, location)}}</div>
</div>
</div>
filterLocation: function(item, location) {
let value = item.item_locations.filter(item_location => {
return item_location.location_id == location.id;
});
var that = this;
that.item_location_exists = value.length;
},
And in template I can do a conditional as item_location_exists equals to 0 or 1.

Razor's Umbraco.media throws error when no image is uploaded

I'm making a bunch of content boxes to render to the master. They all contain a background picture, a heading and content, all are ment to be optional. so if none = empty divs. -> removed.
it all seemed allright i used the #Umbraco.Field for text and #Umbraco.Media(CurrentPage.myMediaAlias).url for the bg picture. Using 'media picker' as datatype.
No problem leaving the heading and content fields blank.
But the problem started when there was no picture defined for the last box.
i got the:
Object reference not set to an instance of an object.
[No relevant source lines]
Since it is supposed to be optional to put in that picture, i would rather want a null back.
The media picker property is not mandatory. How can i get this to work?
#section contentMid2 {
<div class="c-box-wrapper">
<div class="c-box" id="c-box-3" Style="background-image: url(#Umbraco.Media(CurrentPage.box3Bg).Url )" >
<div class="transbox">
<div class="home-head-1"> #Umbraco.Field("mainHeading3") </div>
<div class="content-text1"><p>#Umbraco.Field("mainContent3")</p></div>
</div>
</div>
}
Untested - but something like this should work. They key being to use HasValue
if(#CurrentPage.HasValue("box3Bg"){
<div class="c-box" id="c-box-3" Style="background-image: url(#Umbraco.Media(CurrentPage.box3Bg).Url )" >
}
else{
<div class="c-box" id="c-box-3">
}
OR
#{
var inlineStyle = "";
if(#CurrentPage.HasValue("box3Bg"){
inlineStyle = background-image: url(#Umbraco.Media(CurrentPage.box3Bg).Url )
}
}
<div class="c-box-wrapper">
<div class="c-box" id="c-box-3" Style="#inlineStyle" >
<div class="transbox">
<div class="home-head-1"> #Umbraco.Field("mainHeading3") </div>
<div class="content-text1"><p>#Umbraco.Field("mainContent3")</p></div>
</div>
</div>
</div>
After some debuging and some help from #marco. i realized how to fix it:
<div class="c-box" id="c-box-3" Style="background-image: url(#(Umbraco.Media(CurrentPage.box3Bg.ToString())!=""?Umbraco.Media(CurrentPage.box3Bg).Url:Umbraco.Media(CurrentPage.box1Bg).Url))" >
It's a Shorthand, and still inside the style url: #(theobj!=empty?nah:yah) works like a charm.
But i had to convert theobj .ToString() before comparing or it or else it seems like .Media cant decide if it's int or string. even if the question was if it's nothing in there at all.

How to change autocompleter widget size

I tried the code from the project to change the size of the select box:
<strong>Result Div :</strong>
<div id="formResult" class="result ui-widget-content ui-corner-all">Submit form bellow.</div>
<strong>Topics Div :</strong>
<div id="topics" class="result ui-widget-content ui-corner-all"></div>
<s:form id="form" action="echo" theme="simple" cssClass="yform">
<fieldset>
<legend>Select Box as Autocompleter</legend>
<div class="type-select">
<label for="echo">Echo: </label>
<sj:autocompleter
id="customers"
name="echo"
list="%{customers}"
listValue="name"
listKey="id"
selectBox="true"
selectBoxIcon="true"
onChangeTopics="autocompleteChange"
onFocusTopics="autocompleteFocus"
onSelectTopics="autocompleteSelect"
cssStyle="width:100%;"
/>
</div>
<div>
<sj:submit
targets="formResult"
value="AJAX Submit"
indicator="indicator"
button="true"
/>
<img id="indicator" src="images/indicator.gif" alt="Loading..." style="display:none"/>
</div>
</fieldset>
</s:form>
<br/>
but it doesn't work. I don't know what is the problem with this code.
Looking at generated HTML neither cssStyle nor cssClass of <sj:autocompleter> tag is set to actual input field. But you can use plain CSS to style this input field. Put your <sj:autocompleter> inside of some element to change only specific input then you can use something like that:
.type-select .s2j-combobox-input {
width: 100%;
}
Where type-select is class of wrapper element and s2j-combobox-input is the class of generated input field for the <sj:autocompleter>.

How to Know Available Data from my website for my Google Custom Search

I'm trying to implement a Google Custom Search Engine into my website. So far, I've been able of changing my snippets layout, and show the variables Google shows in its examples:
http://googleajaxsearchapi.blogspot.com.es/2010/04/rendering-custom-data-in-custom-search.html
Well, in the examples, everything looks great, BECAUSE THEY KNOW THE VALUES THEY MAY PRINT. I mean, if you see this snippet:
<div id="mysite_thumbnail">
<div data-if="Vars.thumbnail" class="gs-image-box gs-web-image-box">
<a class="gs-image" data-attr="{href:url, target:target}">
<img class="gs-image" data-attr="{src:thumbnail.src, width:48, height: 48}"/>
</a>
</div>
</div>
it's pretty clear that "Vars" is holding some data GSE is printing. My problem is that I don't know what "Vars" holds, and when developing my view I can't know if the value is there, and what is its name.
So, the question is: How can I print "Vars"? I suppose is a js variable you may obtain from the jsapi, but juss guessing, console.log() was not working for me, :(
Well, I finally found out how to post the data:
From Google Search Engine Api documentation:
https://developers.google.com/custom-search/docs/js/rendering?hl=es&csw=1#richsnip
You only have to add the following code in your snippet:
<span data-body="JSON.stringify(Vars)"></span>
So, you'll have something like:
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// Load the Search API
google.load('search', '1');
// Set a callback to load the Custom Search Control when you page loads
google.setOnLoadCallback(
function(){
new google.search.CustomSearchControl('XXXXXXXXXXXXXXX').draw('cse');
google.search.Csedr.addOverride("mysite_");
},
true);
console.log(google);
</script>
<div style="display:none">
<div id="mysite_thumbnail">
//This will show all Vars content
<span data-body="JSON.stringify(Vars)"></span>
<div data-if="Vars.thumbnail" class="gs-image-box gs-web-image-box">
<a class="gs-image" data-attr="{href:url, target:target}">
<img class="gs-image" data-attr="{src:thumbnail.src, width:48, height: 48}"/>
</a>
</div>
<div data-ifel="Vars.thumbnail == 0" class="gs-image-box gs-web-image-box">
<a class="gs-image" data-attr="{href:url, target:target}">
<img class="gs-image" data-attr="{src:'XXXXX.png', width:115, height: 90}"/>
</a>
</div>
</div>
<div id="mysite_webResult">
<div class="gs-webResult gs-result"
data-vars="{longUrl:function() {
var i = unescapedUrl.indexOf(visibleUrl);
return i < 1 ? visibleUrl : unescapedUrl.substring(i);}}">
<table>
<tr>
<td valign="top">
<div data-if="Vars.richSnippet" data-attr="0"
data-body="render('thumbnail',richSnippet,{url:unescapedUrl,target:target})"></div>
</td>
<td valign="top">
<div class="gs-title">
<a class="gs-title" data-attr="{href:unescapedUrl,target:target}"
data-body="html(title)"></a>
</div>
<div class="gs-snippet" data-body="html(content)"></div>
</td>
</tr>
</table>
</div>
</div>
</div>