By Paul Gresham
The aim of this page to be a simple resource upon which non-programmers can create and adapt velocity templates within their CMS systems. Essentially it should provide a few examples and ideas on how you can get information out of Liferay and dynamically onto a webpage based upon the content you have created.
We'll talk a bit about Velocity and then create an example that allows someone to create an article with a drop down status list that is translated into a traffic-light image when displayed on the website.
links to documents covering the assumptions here for completeness
Once you have found the SAMPLE-ARTICLE, edit it and you will see that you can choose between the two templates, however choosing one or the other will not be visibly different. The difference is only the technology used to 'render' the SAMPLE-ARTICLE. One being XSL and the other VM, or Velocity Macro.
So open up the Template SAMPLE-VM-TEMPLATE and click on the 'Launch Editor' button. You will see a script pop up in a window. The script should look suspiciously like a web page with a load of lines which start with ## before it. Any line beginning with ## is a comment and is ignored by velocity. Lets take a look at the section
<table border="1" cellpadding="8" cellspacing="0" width="600">
<tr>
<td>Sample Text</td>
<td>$sample-text.getData()</td>
</tr>
<tr>
...
Here you can see we have access to the structured content, which has a row of data on it called sample-text. We have to ask sample-text for it's data and in fact we can simplify this quite a bit as velocity provides a bit of magic for us.
<table border="1" cellpadding="8" cellspacing="0" width="600">
<tr>
<td>Sample Text</td>
<td>$sample-text.data</td>
</tr>
<tr>
...
If you insert the sample article on a page somewhere and view it, then edit it to ensure it is using the SAMPLE-VM-TEMPLATE, you should see the article rendered in a big single column table.
What exactly is happening? Well you need to understand the relationship between Articles, Structures and Templates. The article is associated with a structure. The structure defines which fields are available to people creating articles. You can also choose a template, which defines how you want the article to appear.
![]() |
Here you can see on the SAMPLE-ARTICLE that we have chosen a structure (SAMPLE-STRUCTURE), plus a template (SAMPLE-VM-TEMPLATE). In addition to providing us with fields to fill in, the structure also names those fields and we can access the fields in our velocity template using the special notation $ followed by the field name.
The following code snippet should actually be meaningful to you now. Quite simple we can access the fields provided by the structure and format them using plain old HTML.
<table border="1" cellpadding="8" cellspacing="0" width="600">
<tr>
<td>Sample Text</td>
<td>$sample-text.data</td>
</tr>
<tr>
...
<table border="1" cellpadding="8" cellspacing="0" width="600">
<tr>
<td>$sample-text.data</td>
<td>$sample-text-box.data</td>
<td>$sample-text-area.data</td>
<td><img src="$sample-image.data"/></td>
<td>$sample-boolean-flag.data</td>
<td>$sample-selection-list.data</td>
<td>$reserved-article-id.data</td>
<td>$reserved-article-version.data</td>
<td>$reserved-article-title.data</td>
<td>$reserved-article-create-date.data</td>
<td>$reserved-article-modified-date.data</td>
<td>$reserved-article-display-date.data</td>
<td>$reserved-article-author-id</td>
<td>$reserved-article-author-name</td>
<td>$reserved-article-author-email-address</td>
<td>$reserved-article-author-comments</td>
<td>$reserved-article-author-organization</td>
<td>$reserved-article-author-location</td>
<td>$reserved-article-author-job-title</td>
</tr>
</table>
Note the special notation <strong>$reserved-article-XXXX</strong>. All of these give you access to the default fields such as the article ID, It's title, creation date, last modified date and version number. All useful stuff, no?
<tr>
<td>Sample Multiple Selection List</td>
<td>
<b>
#foreach($selection in $sample-multi-selection-list.getOptions())
$selection
<br/>
#end
</b>
</td>
</tr>
The special notation #foreach does exactly what it says on the tin. It moves, one item at a time over a list of items. In this case each item is called $selection and the list is grabbed from inside the multiple select box using the getOptions() method. This is diving into the realms of programming, but you should be able to mindlessly follow the example, a bit of copy and pasting and you'll be right! So if there are three items selected, the velocity macro above will produce something like this. item1<br/> item2<br/> item3<br/>
<tr>
<td>Image</td>
<td><img src="$sample-image.getData()"/></td>
</tr>
Let say we've uploaded three images to a gallery called 'images'. I can obtain the links to those three images and they happen to be in: /image/image_gallery?img_id=1006 /image/image_gallery?img_id=1007 /image/image_gallery?img_id=1008And in this case they are little traffic lights, red, amber and green.
Note: <strong>Must request friendly urls for images. That extra level of indirection would greatly enhance the galleries</strong>
Now I've created a drop down list box in my structured content as follows:
...
<dynamic-element name='status' type='list'>
<dynamic-element name='1007' type='OK'> </dynamic-element>
<dynamic-element name='1006' type='attention'> </dynamic-element>
<dynamic-element name='1008' type='problem'></dynamic-element>
</dynamic-element>
...
And my velocity template can render the image as follows:
...
<tr>
<td>$title.getData()</td>
<td>$detail.getData()</td>
<td><img src="/image/image_gallery?img_id=$status.getData()"/></td>
<td>$reserved-article-version.getData()</td>
</tr>
...
Ok this is great, we've dynamically picked up some images, but what if I wanted the image to be displayed along with the text. Well as we cannot create friendly URLs for images, we're forced to do a bit of hard coding (hard-core liferay-ers may know of other ways, but I don;t). And to avoid making our template really messy, we'll create a little macro. Here are the full listings of my structured content and my template.
<root>
<dynamic-element name='title' type='text'></dynamic-element>
<dynamic-element name='detail' type='text_area'></dynamic-element>
<dynamic-element name='status' type='list'>
<dynamic-element name='OK' type='OK'> </dynamic-element>
<dynamic-element name='Attention' type='attention'> </dynamic-element>
<dynamic-element name='Problem' type='problem'></dynamic-element>
</dynamic-element>
</root>
<html>
<head>
<title>$title.getData()</title>
</head>
<body>
#set ( $iurl = "/image/image_gallery?img_id=" )
#macro( tlight $tl-status )
#if ($tl-status)
#if ($tl-status.equals("OK"))
<img src="$iurl 1007"/><br/>OK
#elseif ($tl-status.equals("Attention"))
<img src="$iurl 1006"/><br/>Attention
#elseif ($tl-status.equals("Problem"))
<img src="$iurl 1008"/><br/>Problem
#end
#else
No Status Given
#end
#end
<table border="0" cellpadding="3" cellspacing="2" width="600">
<tr>
<td>Title</td>
<td>Description</td>
<td align="center">Status</td>
<td>Version</td>
</tr>
<tr>
<td>$title.getData()</td>
<td>$detail.getData()</td>
<td align="center" valign="center">
#tlight( "$status.getData()" )
</td>
<td>$reserved-article-version.getData()</td>
</tr>
</table>
</body>
</html>
#set ( $iurl = "/image/image_gallery?img_id=" )
#macro( tlight $tl-status )
#if ($tl-status)
#if ($tl-status.equals("OK"))
<img src="$iurl 1007"/><br/>OK
#elseif ($tl-status.equals("Attention"))
<img src="$iurl 1006"/><br/>Attention
#elseif ($tl-status.equals("Problem"))
<img src="$iurl 1008"/><br/>Problem
#end
#else
No Status Given
#end
#end
Notice there is no HTML in there at all. The SERVICES-BULLETIN macro is now quite short and sweet:-
<html>
<head>
<title>$title.getData()</title>
</head>
<body>
<table border="0" cellpadding="3" cellspacing="2" width="600">
<tr>
<td>Title</td>
<td>Description</td>
<td align="center">Status</td>
<td>Version</td>
</tr>
<tr>
<td>$title.getData()</td>
<td>$detail.getData()</td>
<td align="center" valign="center">
#parse("$journalTemplatesPath/TRAFFIC-LIGHT-MACRO")
#tlight( "$status.getData()" )
</td>
<td>$reserved-article-version.getData()</td>
</tr>
</table>
</body>
</html>
We've also created some external macros and included them.
It would be nice however, to use velocity to generate a list for us. Unfortunately within Journal, we have limited access to the underlying system and cannot really go any further, without dropping out to code. As this is a tutorial for non-programmers, I will address these issues with the liferay developers and see if we can get the desired hooks into a later version.
If you have some programming knowledge and want to rebuild yourself another installation of liferay take a look at the class com.liferay.portlet.journal.util.JournalVmUtil. I'd suggest using an xml tool that will allow you to query the rss feed as in the ABOUTUS-NEWS example which uses XSL.
permissions
more work needs to be done to document the methods available in these objects
0 Attachments | Average (0 Votes) ![]() ![]() ![]() ![]() |