Developing Templates and Themes using Liferay Portal
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
Contents |
[edit] Building layout templates in Ext
Layout Templates are ways of choosing how portlets will be arranged on a page. Layout templates are usually a grid-like structure and are mostly created with HTML tables. They form the body of a page the large area, where you can drag and drop the portlets to create pages. In short, a layout template describes how various columns and rows are arranged to display the portlets.
As shown in the following screenshot for the use case Tutorial Workshop Home, the web site www.tutorialpubworkshop.com is made up of many workshop pages. Each page consists of a set of portlets. Portlets are arranged in a specific way in pages. For instance, the AROUND THE WORLD page has three portlets: I'm Lola, Our Research is Global, and Our Co-Productions. The whole page is aligned in the centre, while I'm Lola, Our Research is Global, and Our Co-Productions are represented by layout template 1-2 columns. As you can see, Lola's hand is around 25 pixels out of the box. This means that I'm Lola portlet should have padding-left 0 pixel; the Our Research is Global portlet should have padding-left 25 pixels; and the Our Co-Productions portlet should have padding-right 25 pixels with a border on the left side.
A similar situation happens in the web site tutorialpubstreet.com. As shown in the following screenshot for the use case Tutorial Street Home, the web site tutorialpubstreet.com is made up of many street pages. Each page consists of a set of portlets arranged in a specific way. For example, the Home page has five portlets: Holiday Time, Get the most out of..., This holiday season..., Buy OLD SCHOOL DVDs, and Parents. The whole page is aligned in center, while these five portlets are represented as 1-3-1 columns. As you can see, the portlets Holiday Time, Get the most out of..., The holiday season..., and Buy OLD SCHOOL DVDs... should have padding-left 0 pixel; whereas the portlet Parents should have padding-left 25 pixels and padding-right 25 pixels.
The feature of dragging and dropping portlets to build pages is helpful and flexible for experienced users who are familiar with the portal. But some end users, such as content producers, prefer to use predefined layout templates in building pages. For example, the content producers in Palm Tree Publications do not expect to drag-and-drop portlets to create pages. They expect Admin to predefine the layout templates first, and then they just choose one of the layout templates and apply it on a specific page. All of the portlets related to this page as well as the selected layout template should be populated automatically. Then, they just update the content of portlets if applicable. Therefore, the layout templates should be applied in different ways: drag-and-drop, bundle with pages, and so on.
As shown in the following screenshot, a set of predefined layout templates is available for a content producer to build pages. When a content producer chooses a layout template and applies the selected layout template on a page, all portlets associated with the selected layout templates will be populated to this page. After that, a content producer just populates the content of portlets in this page.
As mentioned in previous tutorials, we have discussed how to dynamically apply layout templates to pages. How do we build these layout templates? In this section, we're going to build the layout templates in Ext. By the way, there is also a feature to build layout templates in Plugins SDK. This will be introduced in the coming section.
[edit] Constructing custom layout templates
In brief, a layout template describes how various columns and rows are arranged in pages to display the portlets on top of the portal. By default, the portal comes with several built-in layout templates. But if you have a layout of complex pages as mentioned above, especially for your customized pages, you need to create custom layout templates.
[edit] Experiencing default layout templates
Layout templates are located in the /portal/portal-web/docroot/html/layouttpl/standard and /portal/portal-web/html/custom directories as a series of .tpl files and .png files. By default, there are two groups of layout templates: standard and custom. You can find these two groups of layout templates in the following manner:
1. Locate the XML file liferay-layout-templates.xml in the /portal/portal-web/docroot/WEB-INF folder and open it.
2. Check the <standard> and </standard> XML tags:
<?xml version="1.0"?> <!DOCTYPE layout-templates PUBLIC "-//Liferay//DTD Layout Templates 5.2.0//EN" "http://www.liferay.com/dtd/liferay-layout- templates_5_2_0.dtd"> <layout-templates> <standard> <layout-template id="exclusive"> <template-path> /layouttpl/standard/exclusive.tpl </template-path> <wap-template-path> /layouttpl/standard/exclusive.wap.tpl </wap-template-path> <thumbnail-path> /layouttpl/standard/exclusive.png </thumbnail-path> </layout-template> <layout-template id="max"> <template-path> /layouttpl/standard/max.tpl </template-path> <wap-template-path> /layouttpl/standard/max.wap.tpl </wap-template-path> <thumbnail-path> /layouttpl/standard/max.png </thumbnail-path> </layout-template> <! ignore details --> </standard> </layout-templates>
In the same way, you can find the <custom> and </custom> XML tags as follows:
<custom> <layout-template id="freeform" name="Freeform"> <template-path> /layouttpl/custom/freeform.tpl </template-path> <wap-template-path> /layouttpl/custom/freeform.wap.tpl </wap-template-path> <thumbnail-path> /layouttpl/custom/freeform.png </thumbnail-path> <roles><role-name>User</role-name></roles> </layout-template> <layout-template id="1_column" name="1 Column"> <template-path> /layouttpl/custom/1_column.tpl </template-path> <wap-template-path> /layouttpl/custom/1_column.wap.tpl </wap-template-path> <thumbnail-path> /layouttpl/custom/1_column.png </thumbnail-path> </layout-template> <! ignore details --> </custom>
The code above shows that the standard layout templates include exclusive, max, and pop_up; whereas the custom layout templates include by default freeform, 1_column, and so on. Each layout template is made up of three files: .png for thumbnail icon, .tpl for regular web browsers, and .wap.tpl for the WAP version (Wireless Application Protocol). For instance, the 1_column layout template includes the 1 Column display name, the /layouttpl/custom/1_column.tpl template path, the WAP template path /layouttpl/custom/1_column.wap.tpl, and the /layouttpl/custom/1_column.png thumbnail path.
[edit] Adding customized layout templates
As stated above, the default layout templates are located in the /portal/portal-web/docroot/html/layouttpl/standard and /portal/portal-web/html/custom folders. Each layout template is made up of a .png thumbnail icon, .tpl for regular web browsers, and .wap.tpl for WAP version. The layout templates are registered in /portal/portal-web/docroot/WEB-INF/liferay-layout-templates.xml.
Now let's create customized layout templates in Ext as well. Considering the above use cases Tutorial Workshop Home and Tutorial Street Home, we're going to create two layout templates: tutorial_workshop_home and tutorial_street_home.
The following are the main steps to build the tutorial_street_home layout template:
1. Create a folder named layouttpl under the /ext/ext-web/docroot folder.
2. Create a folder named custom under the /ext/ext-web/docroot/layouttpl folder.
3. Create a tutorial_street_home.png thumbnail icon under the /ext/ext-web/docroot/layouttpl/custom folder.<br.
4. Create a tutorial_street_home.tpl file in the /ext/ext-web/docroot/layouttpl/custom folder and open it.
5. Add the following lines in tutorial_street_home.tpl and save it.
<div id="content-wrapper">
<table class="lfr-grid" id="layout-grid">
<tr id="row-1">
<td class="lfr-column" id="column-1" valign="top" colspan="3"
style="border: 0px solid green; padding-left: 0px; width: 917px; ">
$processor.processColumn("column-1")
</td> </tr>
<tr id="row-2">
<td class="lfr-column thirty" id="column-2" valign="top"
style="border: 0px solid green; padding-left: 0px; ">
$processor.processColumn("column-2")
</td>
<td class="lfr-column thirty" id="column-3" valign="top"
style="border: 0px solid green; padding-left: 0px; ">
$processor.processColumn("column-3")
</td>
<td class="lfr-column thirty" id="column-4" valign="top"
style="border: 0px solid green; padding-right: 0px; ">
$processor.processColumn("column-4")
</td> </tr> <tr id="row-3">
<td class="lfr-column" id="column-5" valign="top" colspan="3"
style="border: 0px solid green; padding-left: 25px;
padding-right: 25px; width: 917px; ">
$processor.processColumn("column-5")
</td> </tr> </table>
</div>
The code above shows a way to specify five evenly spaced columns with a table. Each table cell <td> has an associated CSS class (for example, lfr-column), a style, as well as an ID (for example, column-1). Here it uses style of <td>. You can modify style with different values in order to get a different look and feel. Especially, columns (for example, column-1 and column-5) are arranged by padding-left and padding-right. In addition, the CSS class may be customized by modifying the theme you are using to display the layout.
Then, you can create a tutorial_street_home.wap.tpl file in the folder /ext/ext-web/docroot/layouttpl/custom and add the following lines:
<table>
<tr><td colspan="3">
$processor.processColumn("column-1")
</td></tr>
<tr>
<td>$processor.processColumn("column-2")</td> <td>$processor.processColumn("column-3")</td>
<td>$processor.processColumn("column-4")</td>
</tr> <tr>
<td colspan="3"> $processor.processColumn("column-5")
</td> </tr>
</table>
As shown in the code above, WAP version doesn't have the benefit of CSS and so it settles for five evenly spaced columns. In runtime, the portal will automatically detect the client being used to connect to tutorialpubstreet.com and serve an appropriate layout template. If the client is a phone, it will serve the tutorial_street_home.wap.tpl file. Otherwise, it will serve the tutorial_street_home.tpl file.
The thumbnail icon specifies what the layout looks like. You can customize thumbnail icons tutorial_workshop_home.png and tutorial_street_home.png in an image manipulation program such as GIMP, Adobe Photoshop, and so on.
|
GIMP is the GNU image manipulation program, which is a distributed piece of software for tasks such as photo retouching, image composition, and image authoring. Refer to http://www.gimp.org. |
Similarly, you can create the tutorial_workshop_home layout template. Just create a tutorial_workshop_home.png thumbnail icon, a tutorial_workshop_home.tpl file, and tutorial_workshop_home.wap.tpl.
[edit] Registering layout templates
We have created customized layout templates successfully. Now let's register the above layout templates tutorial_street_home and tutorial_workshop_home:
1. Locate the XML file liferay-layout-templates.xml in the /portal/portal-web/docroot/WEB-INF folder.
2. Copy the XML file liferay-layout-templates.xml from the /portal/portal-web/docroot/WEB-INF to folder /ext/ext-web/docroot/ WEB-INF folder.
3. Locate the XML file liferay-layout-templates.xml in the /ext/ext-web/docroot/WEB-INF folder and open it.
4. Add the following lines before the lines </custom> </layout-templates> in liferay-layout-templates.xml and save it:
<layout-template id="tutorial_street_home" name="Street Home"> <template-path> /layouttpl/custom/tutorial_street_home.tpl </template-path> <wap-template-path> /layouttpl/custom/tutorial_street_home.wap.tpl </wap-template-path> <thumbnail-path> /layouttpl/custom/tutorial_street_home.png </thumbnail-path> </layout-template> <layout-template id="tutorial_workshop_home" name="Workshop Home"> <template-path> /layouttpl/custom/tutorial_workshop_home.tpl </template-path> <wap-template-path> /layouttpl/custom/tutorial_workshop_home.wap.tpl </wap-template-path> <thumbnail-path> /layouttpl/custom/tutorial_workshop_home.png </thumbnail-path> </layout-template>
The code above shows registration of the layout templates tutorial_street_home and tutorial_workshop_home. Each layout template is specified as:
- ID such as
1_Column - Name such as
1Column - Template path for example,
/layouttpl/custom/tutorial_street_home.tpl - WAP template path such as
/layouttpl/custom/tutorial_street_home.wap.tpl - Thumbnail path for example
/layouttpl/custom/tutorial_street_home.png
You can specify WAP layout templates there as well.
By the way, you may be interested in layout template DTD (Document Type Definition). Definitely, you can find details of layout templates DTD in /portal/definitions/liferay-layout-templates_5_2_0.dtd.
As you can see, we have specified the Velocity template, for example $processor, in layout templates. Basically, each Velocity template is a plain text file with simple special characters. These special characters are translated just prior to the server sending the requested web page to the browser. The following are the available (but not limited) variables of the Velocity template, which we can use in layout templates:
| Variable
| Template type
|
|---|---|
| processor
| com.liferay.portlet.layoutconfiguration. util.velocity.TemplateProcessor
|
| request
| javax.servlet.http.HttpServletRequest
|
| pageContext
| javax.servlet.jsp.PageContext
|
| portletConfig
| com.liferay.portlet.PortletConfigImpl
|
| renderRequest
| javax.portlet.RenderRequest
|
| renderResponse
| javax.portlet.RenderResponse
|
| themeDisplay
| com.liferay.portal.theme.ThemeDisplay
|
| company
| com.liferay.portal.model.Company
|
| user/realUser | com.liferay.portal.model.User
|
| layout
| com.liferay.portal.model.Layout
|
| layouts
| java.util.List<com.liferay.portal.model.Layout>
|
| plid
| java.lang.String
|
| layoutTypePortlet
| com.liferay.portal.model.LayoutTypePortlet
|
| portletGroupId
| java.lang.String
|
| locale
| java.util.Locale
|
| timeZone
| java.util.TimeZone
|
| theme
| com.liferay.portal.model.Theme
|
| colorScheme
| com.liferay.portal.model.ColorScheme
|
| portletDisplay
| com.liferay.portal.theme.PortletDisplay
|
For example, the $processor.processColumn("column-1") code is handling the column-1 column. You can find the above Velocity template variables in detail in the insertVariables method of com.liferay.portal.velocity.VelocityVariables under the folder /portal/portal-impl/src.
Great! You have created and registered customized layout templates tutorial_street_home and tutorial_workshop_home successfully. When you deploy the above layout templates and restart the application server, you will see that thumbnail icons for both tutorial_street_home and tutorial_workshop_home layout templates are displayed when you click on Layout Template from the Dock menu.
[edit] Developing layout templates in Plugins SDK
We have discussed how to build layout templates in Ext. We also introduced Plugins SDK in the previous tutorials. Now let's focus on how to develop hot-deployable layout templates in Plugins SDK.
Look at the preceding screenshot. For the Product Home use case, we're going to build a page with a row on the top that says Welcome!, one column in the bottom left with a logged-in message and left navigation bar, a column in the middle right having Product Family Centers and Images (Featured Customer Case Study, Customer Connection, Featured Webinar), and two columns in the bottom right with contents Latest Content and News Forum Topics, respectively. As a content editor, you can flexibly drag-and-drop different portlets to the Product Home page. That is, there is only a small set of layout templates that will be in use for the entire web site Customer Centre. Thus, this layout page could be specified by a hot-deployable layout template.
Moreover, this layout template is reusable for other pages. As shown in the following screenshot, a content editor can view it by thumbnail icon, by clicking on Layout Template from the Dock menu. The thumbnail image Product Home shows what the layout looks like.
Obviously, this kind of layout template could be developed in both Ext and Plugins SDK. But in order to make this layout template hot and deployable, it should be developed in Plugins SDK. In this section, we're going to discuss how to build a hot and deployable layout template in Plugins SDK.
[edit] Building layout templates
First of all, we could create a folder named product-home-layouttpl in the $PLUGINS_SDK_HOME/layouttpl folder. Everything for the use case Product Home will go in the $PLUGINS_SDK_HOME/layouttpl/product-home-layouttpl folder.
In the product-home-layouttpl folder, create another docroot folder and an XML file build.xml. Open it and add the following lines at the beginning of this file:
<?xml version="1.0"?> <project name="layouttpl" basedir="." default="deploy"> <property name="plugin.version" value="1" /> <import file="../build-common-layouttpl.xml" /> </project>
The code above shows a layouttpl project with default target deploy. It takes the plugin.version property with value 1. This property should be imported from the build.${user.name}.properties file as mentioned in Tutorial 3, ServiceBuilder and Development Environments. Meanwhile, it imports a build-common-layouttpl.xml file from a parent folder.
Then in the /product-home-layouttpl/docroot/ folder, create a WEB-INF folder. Further, create an XML file liferay-plugin-package.xml in the /product-home-layouttpl/docroot/WEB-INF/ folder and add the following lines at the beginning of this file:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plugin-package PUBLIC "-//Liferay//DTD Plugin Package 5.2.0//EN" "http://www.liferay.com/dtd/liferay-plugin- package_5_2_0.dtd"> <plugin-package> <name>Product Home Templates</name> <module-id> liferay/product-home-layouttpl/5.2.3.1/war </module-id> <types> <type>layout-template</type> </types> <short-description> This plugin is Product Home layout template. </short-description> <change-log></change-log> <page-url>http://www.tutorial.com</page-url> <author>Tutorial, Inc.</author> <licenses> <license osi-approved="true">MIT</license> </licenses> <liferay-versions> <liferay-version>5.2.0+</liferay-version> </liferay-versions> </plugin-package>
The code above shows the plugin package name as Product Home Templates, and module id as liferay/product-home-layouttpl/5.2.3.1/war, type as layout-template, and so on. The liferay-plugin-package.xml file is used to keep track of versions and compatibility. If the portal was upgraded for example, from 5.2 to 5.3 (or 5.4 or 5.5), you need to replace 5.2 and 5_2 with 5.3 (or 5.4 or 5.5) and 5_3 (or 5_4 or 5_5) respectively. That is, only the major version (for example, 5.2, 5.3, 5.4, 5.5, and so on.) needs to be considered.
By the way, you may be interested in the plugin package DTD.
Fortunately, you can find details of the plugin package DTD in the folder
/portal/definitions/liferay-plugin-package_5_2_0.dtd.
Finally, we need to register the product-home layout template.
Create an XML file liferay-layout-templates.xml in the /product-home-layouttpl/docroot/WEB-INF/ folder and add the following lines at the beginning of this file:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE layout-templates PUBLIC "-//Liferay//DTD Layout Templates 5.2.0//EN" "http://www.liferay.com/dtd/liferay-layout- templates_5_2_0.dtd"> <layout-templates> <custom> <layout-template id="product_home" name="Product Home"> <template-path>/product_home.tpl</template-path> <wap-template-path> /product_home.wap.tpl </wap-template-path> <thumbnail-path>/product_home.png</thumbnail-path> </layout-template> </custom> </layout-templates>
The code above shows registration of the product-home layout template under the custom XML tag with id as product_home, name as Product Home, template-path as /product_home.tpl, wap-template-path as /product_home.wap.tpl, and thumbnail-path as /product_home.png. You can specify WAP layout templates there as well.
Optionally, you could run a script to create a blank layout template project. For example, for the above project, we have a project named product_home and layout template display name Product Home. On Linux or Mac, you would change the directory to $PLUGINS_SDK_HOME/layouttpl and then type the following command:
./create.sh product-home "Product Home"
On Windows, you would change the directory to $PLUGINS_SDK_HOME/layouttpl and then type the following command:create.bat product-home "Product Home"
The above command will create a blank layout template in the folder $PLUGINS_SDK_HOME/layouttpl. In fact, the script uses a predefined ZIP file layouttpl.zip to create a blank layout template with the following Ant command:
ant -Dlayouttpl.name=$1 -Dlayouttpl.display.name=\"$2\" create
[edit] Creating layout templates
We have built a project for the product_home layout template. We have also registered the layout template. As mentioned earlier, this layout template is registered with id as product_home, name as Product Home, template-path as /product_home.tpl, WAP-template-path as /product_home.wap.tpl, and thumbnail-path as /product_home.png. But the files product_home.tpl, product_home.wap.tpl, and /product_home.png do not exist yet. Now, let's create these files for this layout template.
First, create a thumbnail icon file product_home.png in the /product-home-layouttpl/docroot folder. This thumbnail icon specifies what the layout looks like. You can customize the thumbnail icon product_home.png in an image manipulation program such as GIMP, Adobe Photoshop, and so on.
Then create a .wap.tpl file product_home.wap.tpl in the /product-home-layouttpl/docroot folder. The WAP version specifies the arrangement of portlets in a page in WAP devices. You need to add the following lines at the beginning of product_home.wap.tp:
<table>
<tr>
<td colspan="2"> $processor.processColumn("column-1")
</td>
</tr>
<tr>
<td>
$processor.processColumn("column-2")
</td>
<td>
<table>
<tr>
<td colspan="2">
$processor.processColumn("column-3") </td> </tr>
<tr> <td> $processor.processColumn("column-4")
</td> <td> $processor.processColumn("column-5")
</td>
</tr>
</table>
<td>
</tr>
</table>
The code above shows five columns in a table and a sub-table. As you can see, the WAP version doesn't have the benefit of CSS.
Last but not the least, create a .tpl file
product_home.tpl in the folder /product-home-layouttpl/docroot.
This file specifies the arrangement of portlets of a page in a regular web browser.
You need to add the following lines at the beginning of product_home.tpl:
<div id="content-wrapper">
<table class="lfr-grid" id="layout-grid" border="0">
<tr>
<td class="lfr-column" valign="top" colspan="2"
style="border: 0px solid green; padding: 5px: width: 970px; ">
$processor.processColumn("column-1")
</td>
</tr>
<tr>
<td class="lfr-column" style="width: 240px;
padding-right: 15px; " valign="top">
$processor.processColumn("column-2")
</td>
<td class="lfr-column" style="width:7 15px;
padding: 0px; " valign="top">
<table width="100%" cellspacing="0"
cellpadding="0" border="0"> <tr>
<td class="lfr-column" colspan="2" style="width: 715px;
padding: 0px; border: 0px solid green;
" valign="top"> $processor.processColumn("column-3")
</td>
</tr>
<tr>
<td class="lfr-column" style="width: 345px;
padding-right: 12px; border: 0px solid green;
" valign="top">
$processor.processColumn("column-4")
</td>
<td class="lfr-column" style="width: 345px;
padding-left: 13px; border: 0px solid green;
" valign="top">
$processor.processColumn("column-5")
</td>
</tr> </table>
</td>
</tr>
</table>
</div>
The code above shows five evenly spaced columns with a table. Each table cell <td> has a CSS class (such as lfr-column) associated with it, a style, as well as an ID (such as column-5). Here this code uses style of HTML tag <td>. You may want to modify style with different values in order to get a different look and feel. Especially, columns such as column-5 and column-3 are arranged by the width, border, padding-left, and padding-right styles. Again, the CSS class may be customized by modifying the theme you are using to display the layout.
You are set! You can first drop the XML file build.xml in the folder $PLUGINS_SDK_HOME/layouttpl/product-home-layouttpl to the Ant view. Then you can click on the Ant target deploy under layouttpl of the Ant view to deploy this layout template. Before deploying, you may need to clean the previous deployment of the layout template by clicking on the Ant target clean in the Ant view.
[edit] Building themes in Plugins SDK
The web sites tutorialpubstreet.com and tutorialpubworkshop.com have their own look and feel, which is specified by the themes on top of the portal. As mentioned earlier, themes customize the overall look and feel of pages generated by the portal.
As shown in the following screenshot, for the use case Tutorial Street Theme, the tutorialpubstreet.com web site has its own look and feel. For example, all the content will stay in the center of pages. Moreover, the width must be fixed as 917 pixels. All the pages in the web site tutorialpubstreet.com will share the same overall look and feel. Especially, a default MUPPET image will be displayed on the MUPPETS button if current user has not signed in yet. When the user signs in, your portrait image will appear on the MUPPET button.
Similarly, as shown in the following screenshot, the web site tutorialpubworkshop.com has its own look and feel the Tutorial Workshop Theme use case. For instance, all the content will stay in the centre of page and the width must be fixed as 917 pixels. All the pages in the web site tutorialpubworkshop.com will share the same overall look and feel. Note that the Donate icon will become bigger in size if the mouse comes over the SUPPORT US button, and it will shrink back to its normal size if the mouse moves away from the SUPPORT US button. At the same time, the Donate icon is presented via JavaScript and it will change its look and feel at random.
Themes can be shared by any pages of any web site. In other words, the other pages from different web sites can share this overall look and feel if applicable. As shown in the following screenshot, you can choose one of the four themes (Tutorial Street, Tutorial Workshop, Classic, and Social Office) for any page you want. Moreover, these themes should be hot-deployable. Using this feature as a developer, you can make your changes, hot deploy them to the portal, and test it quickly.
In this section we're going to address how to develop and deploy themes in the Plugins SDK environment. We will specially address the general processes to develop and deploy themes, and the above use cases will be used only as examples. In real cases, you can use the same processes to build your own themes for your own web sites.
[edit] Creating a customized theme
A theme uses CSS, images, JavaScript, and Velocity templates to control the whole look and feel of the pages generated by the portal. Thus, when creating customized themes, we need to consider these four groups as well. The tutorial-street-theme theme is made up of a folder _diffs with four subfolders css, images, javascript, and templates; and a folder WEB-INF with the properties file liferay-plugin-package.properties and XML file liferay-look-and-feel.xml. Let's build this customized theme as follows.
[edit] Setting up the theme project
First of all, we need to create a folder named tutorial-street-theme under the folder $PLUGINS_SDK_HOME/themes. Everything for the Tutorial Street Theme use case will go in the folder $PLUGINS_SDK_HOME/themes/tutorial-street-theme.
Under the folder tutorial-street-theme, create another folder docroot and an XML file build.xml. Open this XML file and add the following lines at its beginning:
<?xml version="1.0"?> <project name="theme" basedir="." default="deploy"> <import file="../build-common-theme.xml" /> <property name="theme.parent" value="_styled" /> </project>
The code above shows a project theme with the default target deploy. It takes one theme.parent property with the _styled value. You can find _styled in the folder /portal/portal-web/docroot/html/themes/. Meanwhile, it imports a build-common-theme.xml file from parent folder.
Then, under the folder /tutorial-street-theme/docroot,
create a folder /WEB-INF. Now create an XML file
liferay-plugin-package.properties in the folder
/docroot/WEB-INF and add the following lines at
the beginning of this file:
name=Tutorial Street module-group-id=tutorial module-incremental-version=1 tags= short-description= change-log= page-url=http://www.tutorial.com author=Tutorial, Inc. licenses=AGPL
The code above shows the plugin package name as Tutorial Street, the module group ID as tutorial, the module incremental version as 1, the author as Tutorial, Inc., and so on. Of course, you can have your own settings for above items.
Accordingly, we need to register the tutorial-street-theme theme. Create an XML file liferay-look-and-feel.xml in the folder /docroot/WEB-INF and add the following lines in this file:
<?xml version="1.0"?><!DOCTYPE look-and-feel PUBLIC "-//Liferay//DTD Look and Feel 5.2.0//EN" "http://www.liferay.com/dtd/liferay-look-and- feel_5_2_0.dtd"> <look-and-feel> <compatibility> <version>5.2.0+</version> </compatibility> <theme id="tutorial_street" name="Tutorial Street"> <settings> <setting key="portlet-setup-show-borders-default" value="false" /> </settings> </theme> </look-and-feel>
The code above shows the registration of the theme tutorial-street-theme, with the ID as tutorial_street and name as Tutorial Street. At the same time, a portlet-setup-show-borders-default property key is specified with the value false. This means that Liferay portal will turn off borders by default for all the portlets. Each theme can define a set of settings in order to make it configurable. The liferay-look-and-feel.xml file is also used to keep a track of versions and compatibility. As shown in the code above, if the portal was upgraded from 5.2 to 5.3 (or 5.4 or 5.5) , for example, you need to replace 5.2 and 5_2 with 5.3 (or 5.4 or 5.5) and 5_3 (or 5_4 or 5_5) respectively.
By the way, you may be interested in the Liferay look and feel DTD. You can find its details in /portal/definitions/liferay-look-and-feel_5_2_0.dtd.
Finally, we need to create a folder _diffs in the folder /tutorial-street-theme/docroot. Under the folder _diffs, create four subfolders: css, images, javascript, and templates.
[edit] Create a theme from script
Optionally, you can run a script to create a blank theme project. For example, for the above project, we have a project named tutorial-street-theme and theme display named Tutorial Street. On Linux or Mac, you would change the directory to $PLUGINS_SDK_HOME/themes and then type the following command:
./create.sh tutorial-street "Tutorial Street"
On Windows, you would change directory to $PLUGINS_SDK_HOME/themes and then type the following command:create.bat tutorial-street "Tutorial Street"
The above command will create a blank theme in the $PLUGINS_SDK_HOME/themes folder. In fact, similar to the project of layout template, the script uses predefined ZIP file theme.zip to create a blank theme with the following Ant command:
ant -Dtheme.name=$1 -Dtheme.display.name=\"$2\" create
Similarly, you can build a theme project named tutorial-workshop-theme just like you had built the tutorial-street-theme project.
NOTE: in version 5.3 the theme.zip file does not contain the full set of files and directories needed to build up a customized theme; you must manually complete the theme configuration (the _diff directory structure and files) as explained in the previous section; or you can modify the .zip file adding missing files and directories, for future theme creation by script.
[edit] Building differences of themes
As much as we can say, the best practice of building a customized theme is to put only the differences of customized theme into the folder ${theme-name}/docroot/ _diffs. Here ${theme-name} refers to any theme project name, for example, tutorial-street-theme. Using the best practice, we need to put customized CSS, images, JavaScript, and templates in the folder /_diffs only.
In the folder /_diffs/css, create a CSS file custom.css. We should place all of the CSS that is different from the other files. By placing custom CSS in this file, and not touching the other files, we can be assured that the upgrading of their theme later on will be much smoother. In the folder /_diffs/images, put all customized images with subfolders. For example, create two images: screenshot.png and thumbnail.png to show how a page with the current theme looks like. Further, create a subfolder searchbar and put all search‑related images in this folder /searchbar.
Create a JavaScript file javascript.js in the folder /_diffs/javascript. Liferay portal includes the jQuery Javascript library. Thus, we can include any plugins that jQuery supports in the theme. In the folder /_diffs/templates, create customized template files such as dock.vm, init_custom.vm, navigation.vm, portal_normal.vm, portal_pop_up.vm, and portlet.vm. Note that you can use JSP files in template files under the folder templates. However, you won't have access to the Velocity variables if JSP files were in use.
Cool! When you are ready, you can drop the XML file build.xml in the folder $PLUGINS_SDK_HOME/themes/${theme-name} to the Ant view first. Then just double‑click on the Ant target deploy under theme of the Ant view.
[edit] What's happening after deploying themes?
In general, when you double-click on the Ant target deploy under theme of the Ant view, it will copy all of the files from the folder ${app.server.portal.dir}/html/themes/_unstyled/ to the folder $PLUGINS_SDK_HOME/themes/${theme-name}/docroot/ first. Then it will copy all of the files from the folder ${app.server.portal.dir}/html/themes/_styled/ to the folder $PLUGINS_SDK_HOME/themes/${theme-name}/docroot/ too. Afterwards, it will copy all of the files from the folder $PLUGINS_SDK_HOME/themes/${theme-name}/docroot/_diffs/ to the folder $PLUGINS_SDK_HOME/themes/${theme-name}/docroot/. It means that you will place all of your new and changed files into the folder $PLUGINS_SDK_HOME/themes/${theme-name}/docroot. Here ${theme-name} refers to a real theme project name, for example, tutorial-street-theme.
Afterwards, you will see four folders: css, images, javascript, and templates under the folder $PLUGINS_SDK_HOME/themes/${theme-name}/docroot. Each of these folders will contain all merged files and subfolders from /_unstyled, /_styled, and /_diffs. As mentioned earlier, the theme.parent property is specified with the _styled value in $PLUGINS_SDK_HOME/themes/${theme-name}/build.xml. Of course, you can configure this property with the _unstyled value. Fortunately, you can find details from the XML file $PLUGINS_SDK_HOME/themes/build-common-theme.xml as follows:
<if>
<equals arg1="${theme.parent}" arg2="_unstyled" />
<then>
<copy todir="docroot" overwrite="yes">
<fileset dir="${app.server.portal.dir}/ html/themes/_unstyled" excludes="templates/init.vm"/> </copy>
</then>
<elseif>
<equals arg1="${theme.parent}" arg2="_styled" />
<then>
<copy todir="docroot" overwrite="yes">
<filesetn dir="${app.server.portal.dir}/ html/themes/_unstyled"
excludes="templates/init.vm" />
</copy>
<copy todir="docroot" overwrite="yes">
<fileset dir="${app.server.portal.dir}/ html/themes/_styled"/>
</copy>
</then> </elseif>
The code above shows the process to deploy themes. For /_styled, it just copies all files from /_unstyled to /docroot. For /_styled, it first copies all of the files from /_unstyled to /docroot, and then it copies all of the files from /_styled to /docroot and overwrites all the changes on the folder /docroot from the folder /_styled.
In short, the main technologies used in theme development involve CSS, Velocity, and HTML. CSS provides a great degree of control over the look and feel of the page; Velocity (or optionally JSP) provides a series of templates offering control over the HTML produced; and HTML provides the most common output of a theme template. The portal includes two template themes, _unstyled and _styled, which are the basis for other themes. The _unstyled template contains the default templates and images. Its CSS files only contain placeholders to add formatting rules. _styled adds CSS files with formatting rules. For instance, the classic theme is based on /_unstyled and /_styled and, moreover, it adds different color schemes.
[edit] Putting HTML to use
Themes are organized as a logical file structure. The /templates folder contains the Velocity (or JSP) templates that control the HTML generated by the theme. By default, many of the templates in the /templates directory have been consolidated. The portal_normal.vm file contains the overall site structure, from the opening HTML tag to the closing. It includes the header and footer, two templates (dock.vm and navigation.vm), and also the system files. This file is the main index file that contains the base HTML. The dock.vm file contains the entire HTML for the dock, the file navigation.vm contains the entire HTML for the navigation, and the file portal_pop_up.vm contains the entire HTML structure for pop-up windows. It is similar to the file portal_normal.vm, except it is shown in pop-up windows.
By the way, the file portlet.vm contains the HTML that wraps every portlet, including the portlet title and portlet icons. If you do not want show portlet icons, just comment on the following lines in portlet.vm:
<div class="portlet" id="portlet-wrapper-$portlet_id">
<div class="portlet-topper">
<span class="portlet-title"> $theme.iconPortlet() $portlet_title </span>
<div class="portlet-icons" id="portlet-small-icon-bar_$portlet_id">
#if ($portlet_display.isShowBackIcon())
<a href="$portlet_back_url" class="portlet-icon-back">
#language ("return-to-full-page") </a> #else
//$theme.iconOptions() //$theme.iconMinimize()
//$theme.iconMaximize() //$theme.iconClose()
#end </div>
</div>
<div class="portlet-content">$portlet_content</div>
</div>
The code above shows the portlet content as <div class="portlet-content">$portlet_content</div>. Portlet icons are commented already. In the same way, if in need, you can comment the portlet title and the portlet back URL as well. The HTML is set as the standard mode by default. For example, the following is a sample code is specified in the file portal_normal.vm:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
In addition, it would be better to have Velocity as the default format for templates using Velocity for cleaner code and better maintainability. Here we strongly recommend Velocity for formatting templates. But it is also possible for you to have JSP as default format for templates. If that's the case, just change the .vm extension in the files above to .jsp.
[edit] Experiencing CSS and images
As stated earlier, themes are broken into a logical file structure. The /css folder contains the CSS files of the theme organized in several files, the /images folder contains the images of the theme organized in subfolders by purpose, the /javascript folder contains optional JavaScript code to control behavior aspects, whereas the /WEB-INF folder contains configuration files. As mentioned above, the /templates folder contains the Velocity (or JSP) templates that control the HTML generated by themes.
The following CSS file main.css in the /css folder is the main CSS that includes other CSS files:
@import url(base.css); @import url(application.css); @import url(layout.css); @import url(navigation.css); @import url(portlet.css); @import url(forms.css); @import url(custom.css);
As shown in the code above, the CSS file main.css includes other CSS files; for example, base.css, application.css, layout.css, navigation.css, navigation.css, forms.css, and custom.css. The CSS file base.css contains all of the base generic styling. This styling is used for all elements that are not directly related to another aspect of the site, for example, forms, navigation, and dock. The CSS file application.css has the capacity for all of the styling that is used for application elements, for example, dialogs, inline pop-up windows, tabs, tags, and other elements. The CSS file layout.css accommodates all of the styling related to the layouts. It is fairly low level and should most likely not be edited, unless there is something specific we need. The CSS file navigation.css contains all of the styling related to the navigation, as well as the dock. Whereas, the CSS file portlet .css accommodates all of the styling related to the portlets, including the JSR-168 class-names and the JSR-286 class-names. Moreover, the CSS file forms.css contains all of the CSS styling related to form elements on the page. Last but not least, the CSS file custom.css should contain all the customized CSS that is different from the other files. By placing the customized CSS in this file and not touching the other files, we can be assured that the upgrading of the theme later on will be much smoother.
Further, you can find all of the images of the theme in the /images folder organized in the subfolders by purpose. The /common subfolder normally contains all of the general images; the /dock subfolder contains images for styling the dock; the /messages subfolder contains the images for the different portal messages; the /navigation subfolder contains the images for the navigation styling. While the /portlet subfolder contains images related to the portlet decoration, the /form subfolder contains images related to form elements on the page and the other portlet-specific image subfolders that are used for other purposes.
Now, you can easily reference your themes images directory from CSS without the use of obscure variables. You can also easily feed different CSS styles into different browsers or operating systems, and even different browser versions as shown in the following code (abstracted from /css/form.css):
.ie6 input.text, input.password, .ie6 input.submit, .ie6 input.file, .ie6 input.button {
background-image: url(../images/forms/input_shadow.png);
background-repeat: no-repeat; border: 1px solid;
border-color: #BFBFBF #DEDEDE #DEDEDE #BFBFBF;
font: 1em Arial,Helvetica,Verdana,sans-serif;
padding: 5px 1px; }
As shown in the code above, to reference images directory, you would just put the relative path in this manner: background-image: url(../images/forms/input_shadow.png). The way to select different browsers would be to use .ie, .ie6, .gecko, .safari, and so on. To feed rules to different operating systems, you would provide input of the extension as: .win, .linux, .mac, and so on.
[edit] Using jQuery JavaScript library
Liferay portal includes the jQuery JavaScript library. Thus, you can include any plugins that jQuery supports. Note that the VM template $variable is not supported for better compliance with different portlets.
Inside the javascript.js file in the /docroot/_diffs/javascript/ folder, you will find three different function calls as follows:
jQuery(document).ready( function() {} );
Liferay.Portlet.ready( function(portletId, jQueryObj) {} );
jQuery(document).last(function() {}
);
The preceding code shows the three function calls: jQuery(document).ready, Liferay.Portlet.ready, and jQuery(document).last. The function jQuery(document).ready gets loaded when all the HTML, not including the portlets, is loaded; the Liferay.Portlet.ready function gets loaded after every portlet on the page is loaded; the jQuery(document).last function gets loaded when everything, including the portlets, is on the page.
Besides theme-wide JavaScript, the VM template a also supports page-specific JavaScript. The page settings form provides three separate JavaScript pieces that you can insert anywhere in your theme. You can find the following code for these settings in /portal/portal-web/docroot/html/themes/_unstyled/templates/init.vm.
#set ($typeSettingsProperties = $layout.getTypeSettingsProperties())
#set ($page_javascript_1 = $typeSettingsProperties.getProperty("javascript-1"))
#set ($page_javascript_2 = $typeSettingsProperties.getProperty("javascript-2"))
#set ($page_javascript_3 = $typeSettingsProperties.getProperty("javascript-3"))
In brief, JavaScript has a Document Object Model (DOM). It allows us to grab and interact with different elements on the page. JavaScript also has an Event Model (EM). It allows us to perform actions when a user interacts with the web sites or when changes are made. Browsers handle both DOM and EM in different, and sometimes buggy, ways. Different JavaScript libraries have been developed to compensate for the different ways the browsers behave, and to make it simpler to interact with the page.
jQuery is a JavaScript library that allows us to use CSS selectors (for example #banner, .logo, body, and so on) to select the elements on the page in the same way with CSS. jQuery supports up to CSS 3 (Cascading Style Sheets 3, refer to http://www.w3.org/TR/css3-roadmap).
In the previous tutorial, we have briefly introduced the jQuery pop up. Here, let's take an in-depth look on general usage of jQuery. Firstly, with jQuery we could use CSS selectors to select the elements on the page. For instance, to style all links on a page with CSS, we would use the following code:
a {color: #FAFAFA; text-decoration: none; display: block; }
Similarly, to grab all of the links on a page in jQuery, we would provide input as:
jQuery('a');
Secondly, to execute JavaScript as soon as the page is ready, we would simply pass a function into jQuery directly. In other words, JavaScript will execute as soon as the page has loaded. Suppose we have a link with a muppet class on it as follows:
<a class="muppet" href="http://www.tutorialstreet.com/muppet"> Submit Muppet </a>
We would like to have an alert box to pop up when users click on the above link, and later remove the link so that they cannot see it anymore. To do so, we would use the following JavaScript:
jQuery(funtion(){ jQuiery('.muppet'){
alert('You've clicked on the link MUPPET!');
jQuery(this).remove(); } }
);
Thirdly, jQuery also comes with many built-in effects, for example fading in and out, and sliding elements open and closed. Assume that we have the following HTML:
<a class="show-street-info" href="http://www.tutorialstreet.com/info"> Show Tutorial Street </a>
Using the following JavaScript, when a user clicks on the show-street-info link, the information will slide into view. When they click on it again, it will slide away from view:
jQuery( function() {
jQuery('.show-street-info').click(
function (event){ jQuery('.streetinfo').slideToggle();
} ); } );
Moreover, as mentioned earlier, the portal has a couple of custom events that make working with the page easier:
- Liferay.Portlet.ready(): This event is called whenever a portlet is loaded onto the page
- jQuery(document).last(): This event is called after all the portlets have been rendered onto the page
- jQuery(document).ready(): This event is called when all the HTML, not including the portlets, is loaded onto the page
For more details of jQuery, please check the JavaScript file jquery.js in the folder /portal/portal-web/docroot/html/js/jquery.
[edit] Employ theme settings
The portal defines settings that allow the theme to determine certain behaviors. So far, there are only two predefined settings at the time of writing: portlet-setup-show-borders-default and bullet-style-options. Certainly, this number would grow in the future. The portlet-setup-show-borders-default key shows whether the portal will turn off the borders by default for all the portlets or not. The default value for this property is true. For example, in the tutorial-street-theme theme, we added the following code in ${theme-name}/docroot/WEB-INF/liferay-look-and-feel.xml.
<theme id="tutorial_street" name="Tutorial Street"> <settings> <setting key="portlet-setup-show-borders-default" value="false" /> </settings> </theme>
As shown in the code above, the portlet-setup-show-borders-default key has a false value it means that the portal will turn off the borders by default for all the portlets. The default value is true. This default behavior can be overridden for individual portlets using the liferay-portlet.xml file and Portlet CSS pop-up settings.
The bullet-style-options key shows the bullet style options for theme. You can find the bullet-style-options key in liferay-look-and-feel.xml under the /portal/portal-web/docroot/WEB-INF/ folder.
<theme id="classic" name="Classic"> <! - ignore details --> <settings> <setting key="bullet-style-options" value="1,2" /> <setting key="hello" value="world" /> <setting key="hi" value="mom" /> </settings> <! - ignore details --> </theme>
As shown in the code above, the value must be a comma-separated list of valid bullet styles (for example, 1, 2) to be used by the navigation portlet. You can certainly add customized settings to make the theme configurable. As shown in the code above, two customized settings keys hello and hi are defined in the classic theme.
By the way, these settings (either predefined or customized) can be accessed in the theme templates using the following code:$theme.getSetting("hello");
[edit] Adding color schemes
Color schemes are specified as CSS. With CSS in color schemes, we cannot only change colors, but also choose different background images, different border colors, and so on. You can find color schemes from the liferay-look-and-feel.xml file in the /portal/portal-web/docroot/WEB-INF/ folder as follows:
<look-and-feel> <! - ignore details -->
<theme id="classic" name="Classic">
<root-path>/html/themes/classic</root-path>
<! - ignore details -->
<color-scheme id="01" name="Blue"> <css-class>blue</css-class>
<color-scheme-images-path> ${images-path}/color_schemes/${css-class} </color-scheme-images-path> </color-scheme>
<color-scheme id="02" name="Green"> <css-class>green</css-class> </color-scheme>
<color-scheme id="03" name="Orange">
<css-class>orange</css-class>
</color-scheme>
</theme>
<theme id="control-panel" name="Control Panel">
<root-path>/html/themes/control_panel</root-path>
</theme> <! - ignore details -->
</look-and-feel>
The preceding code shows a theme with ID as classic and name as Classic. The root path of the theme classic is /html/themes/classic. Three color schemes are specified in the theme classic. The 01 color scheme has the name Blue, with CSS class blue, the ${images-path}/color_schemes/${css-class} image path. Similarly, the color schemes 02 and 03 are specified as well. At the same time, another theme with ID as control-panel and name as Control Panel is also specified. The root path of the theme control-panel is /html/themes/control_panel.
Moreover, you can find CSS of color scheme of the theme classic in /portal/portal-web/docroot/html/themes/classic/_diffs/css/color-schemes/. You can also find images of color scheme of the theme classic in /portal/ portal-web/docroot/html/themes/classic/_diffs/images/color-schemes/.
Of course, you can add color schemes in themes, for example tutorial-street-theme and tutorial-workshop-theme. As stated above, you can specify color schemes in liferay-look-and-feel.xml under the folder ${theme-name}/docroot/WEB-INF/, and then add images and CSS for color schemes in the ${theme-name}/docroot/_diffs/css/color-schemes/ and the ${theme-name}/docroot/_diffs/images/color-schemes/ folders, respectively.
[edit] Adhering to WAP standard
Now, let's have a look in detail at the WAP themes. Locate the XML file liferay-look-and-feel.xml in the /portal/portal-web/docroot/WEB-INF/ folder. You will see the following code:
<look-and-feel> <! - ignore details -->
<theme id="mobile" name="Mobile">
<root-path>/wap/themes/${theme-id}</root-path>
<wap-theme>true</wap-theme>
</theme> </look-and-feel>
The code above shows a theme with ID as mobile and name as Mobile. It also specifies the /wap/themes/${theme-id} root path and the WAP theme true. This means that the theme was developed for a mobile device.
You will also notice the addition of a wap folder in /portal/portal-web/docroot/. Locate the mobile folder in the /portal/portal-web/docroot/wap/themes/ folder. To make a theme show up correctly in a mobile device, the following doc type is required in /portal/portal-web/docroot/wap/themes/mobile/templates/portal_normal.vm.
<?xml version="1.0"?> <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.1//EN" "http://www.wapforum.org/DTD/xhtml-mobile11.dtd">
[edit] Adding runtime portlets to a theme
You can especially add runtime portlets to a theme. Suppose that we have portlet ID ${PORTLET_ID} with a value, for example, extComments. Now we're going to add this portlet as a runtime portlet to a theme, for example tutorial-street-theme. To add a runtime portlet to a theme, simply add the following line to the Velocity template:
$theme.runtime("${PORTLET_ID}")
[edit] Using theme, CSS, and JavaScript
As mentioned earlier, themes use CSS, JavaScript, and Velocity templates to control the entire look and feel of the pages that are generated by the portal. Once theme, CSS, and JavaScript are engaged, we should use them in a proper way. Here we list a set of suggestions, as follows.
[edit] Making use of themes
When developing themes, we should take account of the following comments. Note that these suggestions from the best essays practices would make theme development successful and smooth. First, try to use semantic HTML whenever possible and avoid using</code> when the <code><a></code> and <code></code> tags will do.
Secondly, use the <code>
</code> and <code></code> tags appropriately. The <code></code> tag can contain other block level elements such as <code><p></code> and other <code></code>, but <code></code> can only contain inline elements such as images, anchors, and so on.
Then, make sure that an <code>id</code> can only appear once on a page. If you require multiple identifying elements, use a <code>class</code>.
Last but not the least, avoid both classitis and divitis. Divitis is the unnecessary use of the <code></code> tags in markups. As a substitute, remove unnecessary div elements. Likewise, classitis is the overuse of the class attribute, for example placing a class on every child of an element. But instead, use elements and class names sparingly.
[edit] Applying CSS
When developing CSS, we should take the following advices into account. Note that these advices belong to the nice-to-have category.
1. First, avoid using CSS hacks to target different browsers. Liferay portal provides browser selectors that allow us to target a specific browser, as well as a specific version of that browser, using a simple selector namespace such as <code>.ie</code>, <code>.ie6</code>, <code>.firefox</code>, <code>.safari</code>, and so on.
2. Second, strive to use dashes in CSS class names instead of underscores or CamelCasing. (CamelCasing is the practice of writing compound words or phrases in which the words are joined without spaces and are capitalized within the compound.) Then, make an effort to use CamelCasing for <code>id</code>.
[edit] Employing JavaScript
Here we have some recommendations on developing JavaScript. First, we should avoid using global variables in JavaScript files. Global variables can break other scripts inside the portal. They cause endless amounts of conflicts, and also make troubleshooting difficult. To avoid using the global variables, make sure you define variables only inside a function, and always place <code>var</code> in front of that variable when defining it.
Secondly, for the theme, we should use the JSON style to contain all of the functions, properties, values, and so on. For example, if a theme is named <code>tutorial-street-theme</code> in JavaScript, we would place all of the methods and properties inside one object <code>tutorialstreet</code> as follows:
var tutorialstreet={ setUserImagePortrait: function(){
var so = new SWFObject( escape("/cms_services/street/PolaroidSmall.swf"), "PolaroidSmall", "48", "48", "9", "#FFFFFF");
tutorialStreet.addParam("menu","false"); // ignore details
so.write("user_portait");
},
getTimeDate: function(){
// ignore details
var ts_url = "&t=" + ts; return ts_url; },
};
JSON (JavaScript Object Notation) is a lightweight data-interchange format. Refer to http://www.json.org.
[edit] Experiencing the developing and debugging tools
There is a list of tools that you can use to develop and debug the theme, CSS, and JavaScript. First, Firebug is a good tool to view the CSS, which is being applied and inherited to edit the page's CSS live, run JavaScript from a command line, and debug JavaScript with breakpoints, as well as profile tools and track AJAX requests. Refer to http://getfirebug.com/.
Then, you may use IE Developer Toolbar. IE Developer Toolbar is the closest equivalent to Firebug for Internet Explorer. While it is not anywhere near as powerful, it is still a great help to view what CSS is being applied to an object and edit that CSS live. Refer to http://www.microsoft.com.
In addition, you may like DebugBar. DebugBar is a bit like IE Developer Toolbar and Firebug for Internet Explorer. It is quite powerful as it allows us to run JavaScript from a command line and also edit CSS live. Refer to http://www.debugbar.com.
[edit] Customizing Velocity templates in themes
The hot-deployable themes use Velocity for cleaner code and better maintainability by default. In this section, we will first discuss which default Velocity templates are being used in themes. Then we will address how to add customized Velocity templates in both the drop-down menu and the navigation bar. In addition, we will introduce how to set up default customized themes and layout templates in the portal.
[edit] Using default Velocity templates
Themes with the Velocity templates customize the overall look and feel of the portal. As you can see, the dock Welcome Test Test! with a list of drop-down links is specified via Velocity templates. Before logging in, you only see two links in the dock by default: Home and Sign In. After you log in as an admin, you will see a lot of links in the dock. Among many, these links include Home, Control Panel, My Account, Sign out, Add Application, Layout Templates, Manage Pages, Toggle Edit Control, My Places, and so on. Thus, several questions pop up What is the dock with these kinds of links? How does it work? How do we customize Velocity templates? As mentioned earlier, the file <code>dock.vm</code> contains the entire HTML for the dock. Let's have look at the details of dock.
[edit] Experiencing default Velocity variables
First of all, locate the theme <code>${theme-name}</code>, for example <code>tutorial-street-theme</code>, and locate the VM file <code>dock.vm</code> in the <code>${theme-name}/docroot/_diffs/templates</code> folder. When you open it, you will see links with the Velocity templates in the dock as follows:
<div class="lfr-dock interactive-mode">
<h2 class="user-greeting"><span>$user_greeting</span></h2>
<ul class="lfr-dock-list">
#if ($show_home) <li class="home"> <a href="$home_url">$home_text</a>
</li>
#end #if ($show_control_panel)
<li class="control-panel">
<a href="$control_panel_url"> $control_panel_text </a>
</li>
#end #if ($show_sign_in)
<li class="sign-in"> <a href="$sign_in_url">$sign_in_text</a> </li>
#end #* ignore details *#
#if ($show_my_places) <li class="my-places">
<a>$my_places_text</a> $theme.myPlaces() </li> #end
</ul>
</div>
The code above shows the dock with a set of HTML tags:
<code><div></code>, <code><h2></code>, <code><ul></code>, <code><li></code>. It also shows the dock with a list of Velocity templates such as <code>#if</code> and <code>#end</code>. For the user greeting, it uses the <code>$user_greeting</code> Velocity template. For <code>Home</code>, it uses the <code>$show_home</code>, <code>$show_url</code>, <code>$show_text</code> templates. Similarly, it shows templates for <code>Control</code> <code>Panel</code>, <code>My</code> <code>Account</code>, <code>Sign</code> <code>out</code>, <code>Add</code> <code>Application</code>, <code>Layout</code> <code>Templates</code>, <code>Manage</code> <code>Pages</code>, <code>Toggle</code> <code>Edit</code> <code>Control</code>, <code>My</code> <code>Places</code>, and so on.
Then, we would ask, where are these templates specified? Here is the answer: in the file <code>init.vm</code>. Locate the file <code>init.vm</code> in the <code>/portal/portal-web/docroot/html/themes/_unstyled/templates</code> folder and you will see predefined Velocity templates for themes as follows:
#set ($theme_display = $themeDisplay)
#set ($portlet_display = $portletDisplay)
#set ($theme_timestamp = $themeDisplay.getTheme(). getTimestamp())
#set ($theme_settings = $themeDisplay.getTheme(). getSettings())
#* ignore details *#
#set ($user_greeting = $htmlUtil.escape($user.getGreeting()))
#* ignore details *#
#set ($full_templates_path = $fullTemplatesPath)
#* ignore details *#
#if ($show_home)
#set ($home_text = $languageUtil.get($company_id, $locale, "home"))
#set ($home_url = $theme_display.getURLHome())
#if (!$request.isRequestedSessionIdFromCookie())
#set ($home_url = $portalUtil.getURLWithSessionId($home_url, $request.getSession().getId()))
#end #end #* ignore details *#
#parse ("$full_templates_path/init_custom.vm")
The preceding code shows the definition of templates variables: <code>$user_greeting</code>, <code>$show_home</code>, <code>$show_url</code>, <code>$show_text</code>, and so on. More interestingly, it parses the file <code>init_custom.vm</code> from current theme. Thus, we could override the existing template variables in the file<code> init.vm</code> and define new Velocity variables in the file <code>init_custom.vm</code> of our customized themes, for example <code>tutorial-street-theme</code> and <code>tutorial-workshop-theme</code>. We will discuss this usage in the coming section.
You have noticed that a set of template variables are used in the file init.vm as default, which include $themeDisplay, $htmlUtil,$user, $fullTemplatesPath, and so on. Where are these templates variables coming from? They are coming from the Java file VelocityVariables.java. Let's have a deep look at these template variables in the Java file VelocityVariables.java. Locate the Java file VelocityVariables.java in the package com.liferay.portal.velocity under the /portal/portal-impl/src folder and open it. You will see the following code:
// ignore details
velocityContext.put("htmlUtil", HtmlUtil.getHtml());
// ignore details
public static void insertVariables(VelocityContext velocityContext, HttpServletRequest request) {
ThemeDisplay themeDisplay = (ThemeDisplay)request. getAttribute(WebKeys.THEME_DISPLAY);
if (themeDisplay != null) {
Theme theme = themeDisplay.getTheme();
Layout layout = themeDisplay.getLayout();
List<Layout> layouts = themeDisplay.getLayouts();
velocityContext.put("themeDisplay", themeDisplay);
velocityContext.put("company", themeDisplay.getCompany());
velocityContext.put("user", themeDisplay.getUser());
// ignore details
velocityContext.put("fullTemplatesPath",servletContextName + theme.getVelocityResourceListener() + theme.getTemplatesPath());
// ignore details
}
The code above shows a definition of template variables, including $themeDisplay, $htmlUtil, $user, $fullTemplatesPath, and so on.
[edit] Customizing Velocity variables
We have answered the first two questions: What is the dock with these kinds of links, and how does it work. Now let's focus on the third question: How do we customize Velocity templates?
As mentioned in the previous tutorials, we have added the journal article template variable ExtVelocityToolUtilvia <beans> in /ext/ext-impl/src/META-INF/ext-spring.xml. It would be nice to add a template variable extJournalUtil in themes via service events. Afterwards, we could use the template variable extJournalUtil in any themes, including tutorial-street-theme and tutorial-workshop-theme.
Let's customize the template variable extJournalUtil as a pre-service event. First, create a Java file ExtJournalUtil.java in the package com.ext.portal.util under the /ext/ext-impl/src folder. Add the following lines at its beginning:
public class ExtJournalUtil {
public static ExtJournalUtil getInstance() {
return _instance;
}
private ExtJournalUtil() {}
private static ExtJournalUtil _instance = new ExtJournalUtil();
}
As shown in the code above, ExtJournalUtil is specified as a singleton. Then create a package com.ext.portal.events in the folder /ext/ext-impl/src, create a pre-service event ExtServicePreAction.javain the package com.ext.portal.events, and add the following lines:
public class ExtServicePreAction extends Action {
public void run(HttpServletRequest request, HttpServletResponse response) throws ActionException {
Map<String, Object> vmVariables = Collections. synchronizedMap(new HashMap<String, Object>());
vmVariables.put("extJournalUtil", ExtJournalUtil.getInstance());
request.setAttribute(WebKeys.VM_VARIABLES, vmVariables); }
}
The code above shows that the instance of ExtJournalUtil is added as a Velocity variable extJournalUtil. Then, we need to register this pre-service in portal-ext.properties, including ServicePreAction at the end of portal-ext.properties file as follows:
servlet.service.events.pre=com.liferay.portal.events.ServicePreAction ,com.ext.portal.events.ExtServicePreAction
That's it. The Velocity theme templates now include the <code>extJournalUtil variable. Similarly, you can use post-service event <code>ExtServicePostAction.java as well. In short, the pre-service events process before Struts processes the request, while the post-service events process after Struts processes the request. Further, you can customize the other pre/post-service events, for example LoginPreAction.java, LoginPostAction.java, LogoutPreAction.java, LogoutPostAction.java, and so on in at the package com.liferay.portal.events under the /portal/portal-impl/src/ folder.
[edit] Adding customized Velocity templates
We have introduced what the default Velocity templates are using in themes. Now let's consider the second topic: how to add customized Velocity templates in both drop-down menu and navigation bar.
As shown in the following screenshot for the use case, Drop-down Menu the drop-down menu Tools and Applications Online tools >>has three items: Document Tracking , License Key Request, and Software Maintenance Renewal. The Document Tracking (DT) item is visible to any logged-in users. The License Key Request(LKR) item is only visible to the users coming from Admin user group and LKR user group. The Software Maintenance Renewal (SMR) item is only visible to the users coming from Admin user group and SMR user group.
A similar feature is required on the left navigation bar under Online tools and applications. As shown in the above screenshot for the use case Navigation Bar, the left navigation bar has many items: Inflight Data Tracking, Document Tracking, License Key Request, and Software Maintenance Renewal, and so on. The DT and Inflight Data Tracking (IDT) are visible to any logged-in users; the LKR is only visible to the users coming from Admin user group and LKR user group; and the SMR is only visible to the users coming from the Admin user group and SMR user group. In the following section, we're going to show how to implement the two use cases, Drop-down Menu and Navigation Bar, via Velocity templates.
[edit] Using Velocity templates in drop-down menu
To implement the use case Drop-down Menu, we need to add the following user groups after the line <code>ext.ondportal.admin=ONDPortal_Admin</code> in the <code>portal-ext.properties</code> file:
ext.ondapp.lkr=ONDApp_LKR
ext.ondapp.smr=ONDApp_SMR
The code above shows the mappings between user group keys and user group names. The ext.ondportal.admin key has the value ONDPortal_Admin, and the ext.ondapp.lkr and ext.ondapp.smr keys have the values ONDApp_LKR and <code>ONDApp_SMR</code>, respectively.
Next, we need to create three user groups with names ONDPortal_Admin, ONDPortal_LKR, and <ONDPortal_SMR in the User Groups of Control Panel. At the same time, assign expected users into the above user groups, for example assign David Berger to ONDPortal_LKR, and assign Lotti Stein to ONDPortal_SMR.
Now, create a VM file init_custom.vm in ${theme-name}/docroot/_diffs/templates/ and add the following lines at its beginning:
#set ($userGroupService = $serviceLocator.findService(" com.liferay.portal.service.UserGroupService"))
#set ($userGroups = $userGroupService. getUserUserGroups($user.getUserId()))
#set ($show_add_content_admin = false)
#foreach($userGroup in $userGroups)
#if($userGroup.getName().equalsIgnoreCase($propsUtil.get( "ext.ondportal.admin")))
#set ($show_add_content_admin = true)
#end #end
#set ($show_add_content_lkr = false)
#foreach($userGroup in $userGroups)
#if($userGroup.getName().equalsIgnoreCase($propsUtil.get( "ext.ondapp.lkr")))
#set ($show_add_content_lkr = true)
#end #end
#set ($show_add_content_smr = false)
#foreach($userGroup in $userGroups)
#if($userGroup.getName().equalsIgnoreCase($propsUtil.get( "ext.ondapp.smr")))
#set ($show_add_content_smr = true)
#end #end
This code shows how to use the template variable $serviceLocator to find the service $userGroupService for user group. Afterwards, it specifies the template variables show_add_content_admin, show_add_content_lkr, and show_add_content_smr.
Finally, consume the customized Velocity templates $show_add_content_admin, $show_add_content_lkr, and $show_add_content_smrin the VM file navigation.vm under the folder ${theme-name}/docroot/_diffs/templates/ as follows:
#* ignore details *#
#set ($subsubmenu = 1)
#foreach ($nav_child_child in $nav_child.getChildren())
#if ( $show_add_content_admin || ($show_add_content_lkr && $nav_child_child.getName().toLowerCase()
!= $propsUtil.get("sterling.commerce.item.smr").
toLowerCase() )|| ($show_add_content_smr &&
$nav_child_child.getName().toLowerCase()
!= $propsUtil.get("sterling.commerce.item.lkr").
toLowerCase())
#if ($nav_child_child.hasChildren())
<li>
<a onMouseOver="clrTimer();
showLayer('dd$root_menu','dds$root_menu$submenu',
'ddss$root_menu$submenu$subsubmenu')" onMouseOut="setTimer()" href="#">
$nav_child_child.getName() › ›
</a>
</li>
#else <li>
<a onMouseOver="clrTimer(); showLayer('dd$root_menu',
'dds$root_menu$submenu', 'ddss$root_menu$submenu$subsubmenu')
" onMouseOut="setTimer()" href="$nav_child_child.getURL()"
$nav_child_child.getTarget() >
$nav_child_child.getName()
</a>
</li>
#end
#* ignore details *#
In short, we have invoked the portal services through Velocity templates in themes. Liferay portal provides a utility to obtain references to services by $serviceLocator. For example, we can invoke the layoutLocalService, userLocalService, roleService, and <code>userGroupService services when we need them via the following code:
#set ($layoutLocalService = $serviceLocator.findService( "com.liferay.portal.service.LayoutLocalService"))
#set ($roleService = $serviceLocator.findService( "com.liferay.portal.service.RoleService"))
#set ($userLocalService = $serviceLocator.findService( "com.liferay.portal.service.UserLocalService"))
#set ($userGroupService = $serviceLocator.findService( "com.liferay.portal.service.UserGroupService"))
The code above shows how to use service locator to invoke specific services.
You can find the Java file ServiceLocator.java in
the package com.liferay.portal.velocity under
he /portal/portal-impl/src folder.
You can also find $serviceLocator in
the insertHelperUtilities method in the Java
file com.liferay.portal.velocity.VelocityVariables.java
under the /porta/portal-impl/src folder.
ServiceLocator serviceLocator = ServiceLocator. getInstance();
// ignore details
_insertHelperUtility(velocityContext, restrictedVariables, "serviceLocator",serviceLocator);
Similarly, we could invoke the other services existing in the
package com.liferay.portal.service under the
/portal/portal-service/src folder. For example,
these services include the following, but are not limited to:
accountService, contactService, groupService, imageLocalServices,
organizationService,permissionService, and so on.
[edit] Source
The source of this content is Chapter 3: Installing Scalix of Liferay Portal 5.2 Systems Development by Jonas X. Yuan r (Packt Publishing, 2009).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes Essay Writing and criar sites
And Like The Global Information Network and Global Information Network
[edit] Source
The source of this content is Chapter 3: Installing Scalix of Liferay Portal 5.2 Systems Development by Jonas X. Yuan r (Packt Publishing, 2009).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes Essay Writing
And Like The Global Information Network and Global Information Network
