Using the output of a partial as a variable in main template - typo3

Out of this question: Random image with v:iterator.random | cache issue
I use a partial to render non-cacheable stuff (in this case a random image).
I do this with this code in the main-template:
{v:render.uncache(partial: 'Random-Image', arguments: {iterator: images})}
Have this directly in the template outputs the right thing (the url to an image, for example fileadmin/upload/abc.jpg). But if I want to use this as a variable for the src from <f:image it does not work:
<f:image src="{v:render.uncache(partial: 'Random-Image', arguments: {iterator: images})}" alt="alt text" />
Also set as a variable it with v:variable.set does not work.
All I get is: <!--INT_SCRIPT.0081e57d9fd92c925bb35d79fd9d3f79-->
Also when I debug it:
<f:debug>
{v:render.uncache(partial: 'Random-Image', arguments: {iterator: images})}
</f:debug>
I get <!--INT_SCRIPT.0081e57d9fd92c925bb35d79fd9d3f79-->
So, is it possible to use the output of a partial as a variable? Or is it possible to set a variable in the partial and use it in the main-template?

I think you mixed up two things a bit, so I would like to separate your questions:
1) Is it possible to use the output of a partial as a variable?
Yes, like the way you wanted it. Actually you did it.
But let see a test:
There is a Partial : Test/Message
With the content: "It is a test"
Then in the main template you can use something like this:
<div class="test">
<f:if condition="{f:render(partial:'Test/Message')}
== 'It is a test'">
<f:then>Passed</f:then>
<f:else>Failed</f:else>
</f:if>
</div>
In this case you would see "Passed" and if you change the Partial to "It should failed" then you will get "Failed" rendered.
2) Why do you see <!--INT_SCRIPT.0081e57d9fd92c925bb35d79fd9d3f79--> ?
This is a not cached content, so like COA_INT or USR_INT objects in TypoScript.
You can find a function in the typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php its name is INTincScript_process. It is responsible to find such lines in the code and replace them with the not cached content.
It means, if you render your Template, that partial renders only a reference to a not cached object, but not the content itself.
Finally to suggest a solution to the original problem, try to render the whole image inside the partial not just the path to it. So include the into the partial where the v:iterate.random ViewHelper is used. Then the v:render.uncache should mark the whole image block as not cacheable.

Related

Add additional source to Image for further actions

im trying to add an additional source to the dce-image for further actions e.g. an alternate source to perform some JavaScript actions.
The wanted output should look like this:
<img src="path/to/foo.png" data-altsrc="path/to/bar.png">
The problem is the dce i'm using - its iterating through the "images" like this:
<f:for each="{dce:fal(field:'image', contentObject:contentObject)}" as="fileReference">
<f:image src="{fileReference.uid}" treatIdAsReference="1" />
</f:for>
So if I would insert multiple images to this I have no real relation between the images where i know which one is the normal-source and which one is the alternate source.
So there was the possibility to create a section and add two fields for images which we can restrict to one image per field. But there again is the for-loop which doesn't allow me to access the source of the second image for the first image.
It should be a visible relation between these images for the user which is working with the dce.
Im trying to achieve something like this:
<f:for each="{field.images}" as="images">
<!-- want to achieve something like this -->
<f:image image="{images.foo.src}" data-altsrc="{images.bar.src}">
<!-- thats the normal way iterating through images -->
<f:for each="{images.foo}" as="image">
<f:image image="{image}" />
</f:for>
</f:for>
Another idea would be to iterate first through the alternate images and store them into an array and on the main-images to access them but I have no idea if this is even possible also this will restrict the usability of the dce for the user.
Is there any way to achieve this with dce-fluid ?
Thanks in advance
Well, i guess you could extend the sys_file_reference table to add a relation from there. So you would have nested relations (never done that, so you would have to try).
You would also have to add the field to the tca type in the place you need it, that could be a little tricky. Have a look at Tca types overrides.
You could extend the sys_file_reference table with a field "alternative_reference" and add the neccessary TCA setup. Then you would have to retrieve the FileReferences via the FileRepository and use sys_file_reference as foreign table (and of course the sys_file_reference uid as identifier).
FileRepository::findByRelation(
'sys_file_reference',
'alternative_reference',
$uidOfActualSysFileReferenceRecord
);
The other possibility would be a completely new record with 2 different sys_file_reference relations. That record (eg: tx_ext_domain_model_imageset) would have an image_default and image_alternate field, both would be configured as file_relations. That would work for sure.
$defaultImages = FileRepository::findByRelation(
'tx_ext_domain_model_imageset',
'image_default',
$uidOfRecord
);
$alternativeImages = FileRepository::findByRelation(
'tx_ext_domain_model_imageset',
'image_alternative',
$uidOfRecord
);
I assume you do have knowledge about creating records, models, tca and so on.
I personally would prefer the second way, it is more clean and does not change the core-table structures.
Also there is a second image generation viewhelper, that might suite your needs better
<img src="{f:uri.image()}" data-altsrc="{f:uri.image()}" />
But the best way to go might be to write your own ViewHelper for that purpose. You could pass your Object (ImageSet) as parameter and handle all logic there. So your template would be simpler and easier to read/work on.
You have to use data attribute of fluid viewhelper and then get the uri of the image with inline call. Here is how to achieve :
<f:image src="{fileReference.uid}" data="{altsrc: '{f:uri.image(src: \'{fileReference.uid}\', treatIdAsReference: 1}" treatIdAsReference="1"/>
This should do the work.

Using ViewHelper inside a partial path

I'm working on a new extension and my model has the attribute 'type' which can get different strings from the TCA form. Strings only!
The name of the partial that my template should load is inside the 'type' attribute from my model. So here comes my problem. Since TYPO3 4.7.x the .html file names for fluid have to start with an uppercase letter. Inside the 'type' attribute the name of the partial that should be loaded is always lowercase. For that, I wrote a simple view helper that contains only this method:
public function render($string) {
return ucfirst($string);
}
Inside my template I tried to use this view helper for the path to the partial:
{namespace vh=Tx_MyExtension_ViewHelpers}
<f:for each="{obj.subObjects}" as="sub">
<f:render partial="OtherObject/{vh:String.UpperFirstCharacter(string:'{sub.type}')}" arguments="{sub:sub}" />
</f:for>
If I try to load this in the fontend, nothing from my extension will be rendered and there are no error messages anywhere. The problem depends on my view helper, 'cause even if I try to load only this:
{vh:String.UpperFirstCharacter(string:'test')}
{vh:String.UpperFirstCharacter(string:'{sub.type}')}
There is nothing comming back. If I only output {sub.type} it shows me the string that I want, but in lowercase.
Obviously your problem is that you're ViewHelper doesn't do what you want it to do.
First of all, ViewHelper names are to be written in lowerCamelCase.
Second, you don't need to place sub.type in curly braces:
This syntax...
{vh:string.upperFirstCharacter(string:sub.type)}
... should be sufficient.
Fluid will then look for a ViewHelper named
Tx_MyExtension_ViewHelpers_String_UpperFirstCharacter
or namespaced
\My\Extension\ViewHelpers\String\UpperFirstCharacter
Please check that this is the case.
So I found the issue. Fluid can't handle namespaces. So first my ViewHelper looked like this:
<php
namespace TYPO3\MyExtension\ViewHelpers\String;
class UpperFirstCharacterViewHelper ...
Now I changed the name of my class and removed the namespace:
<php
class Tx_MyExtension_ViewHelpers_String_UpperFirstCharacterViewHelper ...
This is how it works. At the moment I work with TYPO3 6.1.6.
Thank you anyway lorenz for your help!
EDIT:
I went fully retarded! Fluid CAN handle namespaces. I just had to set the namespace the right way.
That's how you set the namespace inside the template:
{namespace vh=TYPO3\MyExtension\ViewHelpers}
On top of this comment you can see how my ViewHelper looks like with a namespace.

Images in Extbase - Fluid

I have an standard image upload in TYPO3 Backend, that allows more than 1 image upload.
So I have an image database field with data like that: "image1.jpg,image2.jpg".
In Frontend, I can explode the field, send the array to fluid, and output it in a fluid:for each like that:
<f:image src="uploads/tx_myext/{image}" />
First question is: is there maybe some fancy new Extbase or Fluid Magic, that creates image objects right from database?
Second question: if I have a huge 2MB image and make a fluid:image output with width=100, is it just scaled in browser, or is it really downsized using ImageMagick?
Comma list to array:
Unfortunately as I can see in Extbase 4.7 there is still no ViewHelper for iterating comma separated strings. You have two options: write custom ViewHelper or stay with the way you are using.
TIP: To avoid passing additional params (especially when you have many comma separated fields there and/or using many Partials for rendering the view) I'm adding a public field to my model. Without representation in TCA it will be considered as transient, ie:
/**
* #var array
*/
public $imagesArray;
and then just filling it in controller right before assigning so I can access it as {project.imagesArray} in the view:
public function showAction(Tx_Myext_Domain_Model_Project $project) {
$project->imagesArray = explode(',', $project->getImage());
$this->view->assign('project', $project);
}
view
<f:for each="{project.imagesArray}" as="image">
<f:image src="uploads/tx_myext/{image}" width="200" height="200m" alt="" />
</f:for>
Most probably you are using quite similar approach...
Image resizing:
It's easiest just to ... check. ImageMagick hashes the name of the resized image and stores it in the temp folder by default, so if in code preview you see the path like: typo3temp/pics/cd27baa408.jpg instead of uploads/tx_myext/photo123.jpg that means it was converted with IM. And yes, image ViewHelper uses the IM.
You can even add perform simple calculations by giving value as width="200m" or width="200c" from viewhelper's phpdoc: See imgResource.width for possible options
Now I created a ViewHelper in Typo3 Forge as I think processing of images as they come from database would be quite usefull.
And I added imageLinkWrap for JS Window.
http://forge.typo3.org/issues/46218

Parameter and view naming collisions in Play/Scala templates

I am new to Play Framework and still trying to wrap my head around some things with the new Scala template engine.
Let's say I have the following package structure:
app/
app/controllers/Items.scala
app/models/Item.scala
app/views/layouts/page.scala.html
app/views/item/show.scala.html
app/views/item/details.scala.html //partial
And this is my item/show template:
#(item: Item, form: Form[Item])(implicit flash: Flash)
#layout.page() {
#*want to include details partial, wont work due to item param*#
#item.details(item)
}
Since including another template (e.g. including item/details above) is the exact same syntax as accessing a template parameter (e.g. item above), obviously this existing naming convention won't work without something changing.
I know I can rename my "app.views.item" package to "app.views.items", and rely on singular/plural forms to differentiate the view from the param name, but this does not seem like a very straightforward solution. Also what if I really want the parameter name to be the same as the view package?
One idea I have is to prepend all my views with an extra top level package:
app/views/views/item/details.scala.html
So the include syntax would be #views.item.details(), but again this is obviously a hack.
What is a good way to avoid this issue? How can I better organize my code to avoid such naming collisions?
Most other template engines use operations like "include" or "render" to specify a partial include. I don't mean to offend anyone here, but is the Play Scala template engine syntax so terse that it actually dictates the organization of code?
3 solutions:
First
Typpicaly for partial templates you should use tags as described in the docs, where app/views/tags folder is a base:
file: app/views/tags/product.scala.html
in the templates (no initial import required in the parent view full syntax will allow you to avoid name-clash: #tags.packageName.tagName()):
<div id="container">
#tags.product(item)
</div>
Of course in your case you can also use packages in the base folder
file: app/views/tags/item/product.scala.html
<div id="container">
#tags.item.product(item)
</div>
I'm pretty sure that'll solve your problem.
Second
To avoid clash without changing package's name you can just rename the item in your view, also I recommend do not use a form name for the Form[T] as it can conflict with helpers:
#(existingItem: Item, existingItemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
#item.details(existingItem)
}
Third
If you'll fill your Form[Item] before passing to the view with given Item object, you don't need to pass both, as most probably you can get data from the form:
#(itemForm: Form[Item])(implicit flash: Flash)
#layout.page() {
<div>Name of item is: #itemForm("name").value (this is a replacemnet for ##existingItem.name </div>
#item.details(itemForm)
}
Of course in you product.scala.html you'll need to change the #(item: Item) param to #(itemForm: Form[Item])

Using <wicket:message> tag to produce partially formatted text

I've read about wicket:message here, but can't seem to make it do everything I'd like.
Say I have a HTML page with <wicket:message key="text"/> and a properties file containing text=Blah blah: important point, foo bar. I'm wondering how to make part of the text bold (or apply arbitrary CSS to it), to achieve output like:
Blah blah: important point, foo bar
Note that none of this is actually dynamic, so I wouldn't want to do anything in Java, if that can be avoided.
I've tried nesting tags with something like the following, but no luck.
<wicket:message key="text">
<span class="bold"><wicket:message key="text2"/></span>
</wicket:message>
text=Blah blah: ${text2}, foo bar
text2=important point
Is this even possible in Wicket without 1) injecting the formatted part from Java side or 2) just splitting the text into (in this case) three different properties?
The easiest way is to put the tags inside your localization file:
text=Blah blah: <strong>text2</strong>, foo bar
You could also use a Label and a ResourceModel to replace it later:
text=Blah blah: [b]text2[/b], foo bar
And in your model getObject(), or in your Label:
string.replace("[b]", "<strong>");
string.replace("[/b]", "</strong>");
Or, even better, try to reuse a Markdown implementation in your Label.
I've managed to do this for my own application, albeit with a rather ugly hack. I did it by exposing a customized version of WicketMessageResolver.
Here's what to try:
Wholesale copy and paste org.apache.wicket.markup.resolver.WicketMessageResolver into your own class (say com.acme.CustomWicketMessageResolver) (the hack begins!)
Inside your CustomWicketMessageResolver change
WicketTagIdentifier.registerWellKnownTagName( "message" ); to something else like WicketTagIdentifier.registerWellKnownTagName( "msg" );.
Inside of
private void renderMessage(final MarkupStream markupStream, final ComponentTag openTag, final String key, final String value), you'll find the line getResponse().write( text );.
Immediately before that line you have the opportunity to screw around with the value of "text". There, I do something like text = MyLabelUtils.replaceWikiMarkup(text) which post-processes some wiki-like markup syntax used by the content authors for my application.
For example, I use this method to take a Label using a ResourceModel pointing to the key:
propertyKey=I found the answer on [acronym SO].
and a render it as
I found the answer on <acronym title="Stack Overflow">SO</acronym>.
and that method handles i18n and all that fun stuff.
You can, of course, extend that wiki syntax (or anything similar) to be as simple or complex as you'd need.
Note that you'll have to change <wicket:message key='foo'> to <wicket:msg key='foo> in all of your markup files (or at least in ones where you want this behaviour).
I'd obviously prefer a more standard way to customize the behaviour of the built-inwicket message resolver, but if you need this functionality in a pinch, like I did, this will work for now.
If you need something more standard, you could raise the issue on the Wicket mailing list. It's pretty good.
Starting from Wicket 1.4 you can nest components within a wicket:message element. For example:
<wicket:message key="myKey">
This text will be replaced with text from the properties file.
<span wicket:id="amount">[amount]</span>.
<a wicket:id="link">
<wicket:message key="linkText"/>
</a>
</wicket:message>
Then
myKey=Your balance is ${amount}. Click ${link} to view the details.
linkText=here
and
add(new Label("amount",new Model("$5.00")));
add(new BookmarkablePageLink("link",DetailsPage.class));
Results in:
Your balance is $5.00. Click here to view the details.
So maybe, nesting <wicket:message>s without a component could work as well. Not sure.
Source: https://cwiki.apache.org/confluence/display/WICKET/Wicket%27s+XHTML+tags#Wicket%27sXHTMLtags-Elementwicket%3Amessage