Bloggers recientes

Matthew Draper

7 Mensajes
22 de mayo de 2017

Santiago Pérez de la Cámara

1 Mensajes
19 de mayo de 2017

Minhchau Dang

11 Mensajes
18 de mayo de 2017


1 Mensajes
18 de mayo de 2017

David H Nebinger

51 Mensajes
17 de mayo de 2017

Jan Eerdekens

15 Mensajes
14 de mayo de 2017

Madeline Dickson

1 Mensajes
13 de mayo de 2017

Neil Jin

20 Mensajes
12 de mayo de 2017

Yanan Yuan

1 Mensajes
8 de mayo de 2017

Jonathan Lundy

2 Mensajes
18 de abril de 2017

Liferay and Monator Roadshow in Stockholm 30/1

23 de enero de 2014 Por Erik Andersson

With the rapidly evolving behavior of consumers and business customers, all organizations are faced with the challenge to create a unique experience for customers and users. Customer Engagement is about a customer's interaction with an organization and its products or services for the purpose of mutual value creation. 

Join us at this free roadshow to learn how Liferay can help you redefine the way you interact with your customers and users.

The event will take place at the World Trade Center in Stockholm, Thursday 30/1 13.00 - 17.00.

Sign up for the event here

More information about the roadshow in our pressrelease (in Swedish).

Note - the event will be in Swedish.

Looking forward to seeing you!

A Day of Liferay - Freemarker and Liferay

General Blogs 9 de abril de 2013 Por Erik Andersson


During our (Team Monator) 30 minutes slot at A Day of Liferay, my colleague Andreas Magnusson will talk about Freemarker and Liferay. More specifically he will discuss and show an awesome Freemarker template loader implementation with Spring Portlet MVC. With this implementation your portlet views can live as content in the Document and Media Library in Liferay Portal. This allows you to take advantage of pre-built Liferay features such as versioning and workflows. Also, Andreas will show how you can use Liferay Sync for live editing your views.
Join us tomorrow (Wednesday) at 2PM CEST. More info can be found here.
Andreas first blog post about Freemarker can be found here. Subsequent posts will follow in the near future.

Liferay Navigation Recipes – Part 1

General Blogs 27 de abril de 2012 Por Erik Andersson

Building portals, navigation naturally becomes an important building block of your implementation. Liferay comes with great support for navigation as is – the absolutely most common way of implementing navigation in a Liferay portal is to iterate through the top site pages in the theme (Velocity or FreeMarker) and using the Navigation Portlet for secondary navigation. Sometimes, however, your site requires navigation that is not covered through the existing means of navigating a Liferay portal. In our projects we have used numerous ways to handle different navigation scenarios. This is the first entry in a series of posts where I plan on expanding further on some of these examples.

Grouped Navigation

On a recent project, we had a design that implemented business areas in the normal main navigation in a slightly different way than other pages:

grouped navigation

The business areas were to be placed in the main navigation, but should be grouped to the left of the other links. Also, the client wanted the ability to change names and friendly URLs of the business areas, and add/remove business areas.

To cater for this, we grouped the business areas into one page that we named “Business Sections” with the friendly URL “/business-sections”:

  • Business Sections (/business-sections, hidden)
    • Business Area 1 (/business-area-1, visible)
    • Business Area 2 (/business-area-2, visible)

The main page was set as hidden so that it was not included in the normal iteration of pages in navigation.vm in the theme. Also, the page type was set as “link-to-page”, linked to the first child page (Business Area 1). Thus, if someone happens to hit the URL “../business-sections”, they would be sent to the page for “Business Area 1”. In navigation.vm in the theme, logic was added that pulls all the child pages of the page with the friendly URL “/business-sections” (using Liferay services from the theme) and displays them before the normal page iteration loop. Also, the last list item of the business-section-pages was given a CSS class that would allow for an extra margin.

Here is an example of the code in Velocity:

## Define variables (in init_custom.vm)
## Null variable
#set($null = $some-never-used-variable-name)
## Url prefix
#set($url_prefix = "")
    #set($url_prefix = "/group")
    #set($url_prefix = "/web")
#set($url_prefix = $url_prefix + $page_group.getFriendlyURL())
## Business section url
#set($friendly_url_business_sections = "/business-sections")
## Get business section pages
#set($business_sections_parent_layout = $layoutLocalService.getFriendlyURLLayout($group_id, $layout.isPrivateLayout(), $friendly_url_business_sections))
#set ($business_sections_layouts = $null)
#if($business_sections_parent_layout != $null)
    #set ($business_sections_layouts = $layoutLocalService.getLayouts($group_id, $layout.isPrivateLayout(), $business_sections_parent_layout.getLayoutId()))
## Iterate business section layouts (in navigation.vm)
#set($business_sections_ticker = 1)
#foreach($business_sections_layout in $business_sections_layouts)
    #set($curFriendlyURL = $business_sections_layout.getFriendlyURL())
    #set($curURL = $url_prefix + $curFriendlyURL)
    #set($curListCss = "")
    ## Mark as selected if this is the current page
    #if($curFriendlyURL == $layout.getFriendlyURL())
        #set($curListCss = "selected")
    #elseif($business_sections_layout.isChildSelected(true, $layout))
        #set($curListCss = "selected") 
    ## Mark as last, if this is the last business section page
    #if($business_sections_ticker == $listTool.size($business_sections_layouts))
        #set($curListCss = $curListCss + " last")
    <li class="$curListCss">
        <a href="$curURL">$business_sections_layout.getName()</a>

Now, this should work fine. But what if we are using a virtual host on the page? We could just emit the $url_prefix parameter in the url. But this is not a solution we were satisfied with. We wanted the navigation to work no matter if a virtual host was used or not. So we added the following check when setting the $url_prefix in init_custom.vm: 

#set($layoutSetLocalService = $serviceLocator.findService("com.liferay.portal.service.LayoutSetLocalService"))
#set($current_layout_set = $layoutSetLocalService.getLayoutSet($group_id, $layout.isPrivateLayout()))
#set($current_layout_set_virtual_host = $current_layout_set.getVirtualHostname())
#set($hasVirtualHost = false)
#if($current_layout_set_virtual_host != "")
    #set($hasVirtualHost = true)
#set($url_prefix = "")
        #set($url_prefix = "/group")
        #set($url_prefix = "/web")
    #set($url_prefix = $url_prefix + $page_group.getFriendlyURL())

Now the navigation works in both cases. When there is no virtual host, the URL prefix (for example /web/guest) is added to the URL. When there is no virtual host, the prefix is omitted.

Although the scenario you’re facing might not be exactly the same as the one I’m covering above, I hope my examples will provide you with some valuable insights that can help you on your way.


Rich text editor in custom portlet

General Blogs 16 de noviembre de 2011 Por Erik Andersson

Ever wanted to use a rich text editor (RTE) such as the CK Editor in your custom portlet?

Implementing an RTE in your view is (almost) as simple as using a jsp-tag:

<aui:field-wrapper label="description">
    <liferay-ui:input-editor name="descriptionEditor" toolbarSet="liferay-article" initMethod="initEditor" width="200" />
    <script type="text/javascript">
        function <portlet:namespace />initEditor() { return "<%= UnicodeFormatter.toString("default content") %>"; }

The liferay-ui:input-editor tag does not have a label attribute. To include a label for the RTE, wrap the tag in a aui:field-wrapper tag as shown above.

Also, the liferay-ui:input-editor needs an initMethod defined in javascript that sets the initial value of the RTE. In my example above, the RTE will be initialized with the value "default content". In your own view, obviously you would want to exchange "default value" for a bean value.

Editor toolbar

Now, the code above works great and will provide you with a toolbar (the set of actions/operations in the editor) that looks like the one used when editing wcm-articles.

Liferay comes with four different predefined toolbar sets:

  • liferay
  • liferay-article
  • email
  • edit-in-place

Each toolbar sports its own set of actions/operations. The most slimmed one being the email toolbar set.

The toolbar sets are defined in a file called ckconfig.jsp which you'll find in /webapps/ROOT/html/js/editor/ckeditor/ in your Liferay bundle.

Changing a predefined toolbar

The toolbar set called "liferay-article" is defined in ckconfig.jsp like this:

CKEDITOR.config.toolbar_liferayArticle = [
    ['Styles', 'FontSize', '-', 'TextColor', 'BGColor'],
    ['Bold', 'Italic', 'Underline', 'Strike'],
    ['Subscript', 'Superscript'],
    ['Undo', 'Redo', '-', 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'SelectAll', 'RemoveFormat'],
    ['Find', 'Replace', 'SpellChecker', 'Scayt'],
    ['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
    ['Link', 'Unlink', 'Anchor'],
    ['Image', 'Flash', 'Table', '-', 'Smiley', 'SpecialChar', 'LiferayPageBreak']

Thus, if we would like to remove the option for TextColor, we would need to remove this entry in the definition. This can be done by replacing the ckconfig.jsp file with a custom-jsp hook. If you don't know how to implement a custom jsp hook, you can check this wiki page.

Adding a new toolbar

Similar to the procedure above, you may add a new custom toolbar by adding a toolbar definition to the ckconfig.jsp file with a custom-jsp hook. Let's create one called "slimmed" that is just a simple editor with the option to make text bold, italic and underline. Also let's add the option to insert links:

CKEDITOR.config.toolbar_slimmed = [
    ['Bold', 'Italic', 'Underline'],
    ['Link', 'Unlink']

Deploy your custom jsp hook. Now change your liferay-ui:input-editor to use the slimmed toolbar set:

<aui:field-wrapper label="description">
    <liferay-ui:input-editor name="descriptionEditor" toolbarSet="slimmed" initMethod="initEditor" width="200" />
    <script type="text/javascript">
        function <portlet:namespace />initEditor() { return "<%= UnicodeFormatter.toString("default content") %>"; }

That's it. Your customized RTE is being used in your custom portlet.

Cheers, Erik

Using themeDisplay in javascript, but be aware of types

General Blogs 19 de mayo de 2011 Por Erik Andersson

Hi everyone,

Having worked with Liferay, you are probably well aware of the useful ThemeDisplay. The ThemeDisplay object can be accessed through javascript as well - a global variable called themeDisplay. While you don't have as much information on the javascript version of themeDisplay, you can still get some very useful information from the object. Check it out yourself by logging to the console (using Firebug):

AUI().ready('',function(A) {

However, beware of one thing. The attributes available through the javascript version of themeDisplay are strings. This could bring some serious confusion when working with the attribute. Consider the following code:

AUI().ready('',function(A) {
    var isPrivateLayout = themeDisplay.isPrivateLayout();
    if(isPrivateLayout) {
        console.log('I am a private layout.');
    else {
        console.log('I am a public layout.');


If you visit a public layout in Liferay, you would assume that "I am a public layout" would be logged to the console. But since the attributes accessed through themeDisplay are of the type string, the if statement will always be evaluated as true, since the variable isPrivateLayout will always have a value (either 'true' or 'false').

You can check type by running for example:

Now, some might think, this is easy, let's just double negation (!!) to type convert the string:

AUI().ready('',function(A) {
    var isPrivateLayout = !!(themeDisplay.isPrivateLayout()); // Evaluates to true
    if(isPrivateLayout) {
        console.log('I am a private layout.');
    else {
        console.log('I am a public layout.');


This won't work, however, since in javascript any string that is not empty will evaluate to true. Same thing would go for parsing the string through the Boolean operator:

var isPrivateLayout = Boolean(themeDisplay.isPrivateLayout()); // Evaluates to true

So what do we do? The best way is to set the value of isPrivateLayout using string comparision with the conditional operator:
var isPrivateLayout = (themeDisplay.isPrivateLayout() == 'true') ? true: false;

This says that if the value returned from themeDisplay.isPrivateLayout() has the string value 'true' then the variable isPrivateLayout should be true. Otherwise the value should be false.


Edit 2011-09-28

Just discovered that the discussion above does not apply to all properties accessible throught the ThemeDisplay object. The isSignedIn (themeDisplay.isSignedIn() ) function will return a boolean, and not a string.

As described above, you can check the type of each property using the following:

Introduction, Alloy UI and YUI3 console

General Blogs 16 de febrero de 2011 Por Erik Andersson

Hi all, thanks for stopping by my blog here at Liferay. This being my first post, I'll start by introducing myself to those who yet doesn't know me. My name is Erik Andersson and I'm a co-founder and UI-lead at Monator, which is a Liferay Service Partner and Training Partner in Sweden.

Being responsible for UI-development at Monator, my blog will naturally be focused on UI development with Liferay. Especially, I will aim to write about Liferay's awesome new UI framework Alloy UI (AUI). Hope I can help shed some light into how stuff works in AUI, and give you some tips on how to get started and gain speed on working with the framework.

I know Alloy can be a tough ride to start, but the more you dig into Alloy (and YUI3 of course), the more you see its beauty and power. Promise. With that said, if you guys have any area that you find interesting or in need of more explanation, please leave a comment and I'll try to cover that in a post (given that I feel that I have something to contribute on the topic =)).

I'll end this first post with a tip on how to activate logging with the YUI console. As you all know, debugging and javascript usually don't go very well together. On Firefox we have at least Firebug which is an eternal blessing for us frontend developers. Other browsers have come some way and also have plugins similar to Firebug. Even IE can be debugged with the Developer Tools. Safe to say, however, you often want more.

Enter the YUI console. Now some of you might ask, what does he mean with YUI, wasn't this blog to be about Alloy? Well AUI is a wrapper for YUI3. This means that all the modules, widgets, plugins that are included in YUI3 can be used in AUI (and thereby Liferay). And YUI3 has this useful module called Console. How can you use it? It's as simple as including the console in the AUI dependency list when initiating your AUI sandbox. Now the console module will load and we can create a console:

AUI().ready('aui-base', 'console', function(A) {
    new A.Console({
        height: '250px',
        newestOnTop: false,
        style: 'block',
        visible: true,
        width: '600px'

Now we created a global console, which we can use to log stuff in our javascript code. For those familiar with Firebug's console.log, the equivalent for the console (with AUI) would be:

A.log('This is my log message.');

You can read more about the console module at the official YUI3 documentation page. If you want your console to be more stylish (like the examples on the YUI3 documentation), include the console-core.css stylesheet which can be found in the yui3 library.

That's it for now, hope that you'll stop by soon again.

Mostrando 6 resultados.
Elementos por página 20
de 1