When working with eXo, it is important to not modify the source code. This will ensure compatibility with future upgrades, and will simplify support.
To customize your portal, you need to create an extension project by providing your own artifacts as a set of wars/jars/ears.
A custom extension contains two mandatory items:
extension webapp: contains resources and kernel configurations.
extension activator jar: identifies your webapp as a dependency of the portal container.
A sample extension package is provided here: http://anonsvn.jboss.org/repos/gatein/portal/trunk/examples/extension/
Once you have modified the sample extension to build your own, use "maven clean install" to create the archive files.
To deploy your extension in Tomcat, follow these steps:
Add the file sample-ext.war from sample/extension/war/target/ to the tomcat/webapps directory.
Add the folder starter from starter/war/target/ to the tomcat/webapps directory.
Rename the directory (unzipped folder) starter to starter.war.
This will only work if the starter.war is the last war file to be loaded, so you may need to rename it if your war files are loaded in alphabetical order.
Add the jar file exo.portal.sample.extension.config-X.Y.Z.jar from sample/extension/config/target/ to the tomcat/lib directory.
Add the jar file exo.portal.sample.extension.jar-X.Y.Z.jar from sample/extension/jar/target/ to the tomcat/lib directory.
For JBoss deployment and more details, refer to the Reference Guide.
You can create as many pages as you want within a single portal. Permissions can be defined to make them visible only to specific groups and/or users. This chapter describes how to define this structure.
The configuration of the "classic" portal can be found in the directory /src/main/webapp/WEB-INF/conf/sample-ext/portal/portal/classic of your extension webapp.
Portal:
The portal.xml file describes the layout and portlets common to all the pages of the portal.
<?xml version="1.0" encoding="ISO-8859-1"?>
<portal-config
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.gatein.org/xml/ns/gatein_objects_1_0 http://www.gatein.org/xml/ns/gatein_objects_1_0"
xmlns="http://www.gatein.org/xml/ns/gatein_objects_1_0">
<portal-name>classic</portal-name>
<locale>en</locale>
<access-permissions>Everyone</access-permissions>
<edit-permission>*:/platform/administrators</edit-permission>
<properties>
<entry key="sessionAlive">onDemand</entry>
</properties>
<portal-layout>
<portlet-application>
<portlet>
<application-ref>web</application-ref>
<portlet-ref>BannerPortlet</portlet-ref>
<preferences>
<preference>
<name>template</name>
<value>par:/groovy/groovy/webui/component/UIBannerPortlet.gtmpl</value>
<read-only>false</read-only>
</preference>
</preferences>
</portlet>
<access-permissions>Everyone</access-permissions>
<show-info-bar>false</show-info-bar>
</portlet-application>
<portlet-application>
<portlet>
...
</portlet>
</portlet-application>
<portlet-application>
<portlet>
...
</portlet>
</portlet-application>
<page-body> </page-body>
<portlet-application>
<portlet>
...
</portlet>
</portlet-application>
</portal-layout>
</portal-config>
As you can see, each portlet can be configured with a set of preferences, which will be further detailed.
Pages:
The pages.xml file is used to describe the content of the pages of your portal. In other words, what will be inside the <page-body> tag of the portal.xml file above. Here is an example of the classic portal pages.xml.
<page>
<name>homepage</name>
<title>Home Page</title>
<access-permissions>Everyone</access-permissions>
<edit-permission>*:/platform/administrators</edit-permission>
<container id="ClassicBody" template="system:/groovy/portal/webui/container/UITableColumnContainer.gtmpl">
<access-permissions>Everyone</access-permissions>
<container id="ClassicLeft" template="system:/groovy/portal/webui/container/UIContainer.gtmpl">
<access-permissions>Everyone</access-permissions>
<portlet-application>
<portlet>
<application-ref>presentation</application-ref>
<portlet-ref>SingleContentViewer</portlet-ref>
<preferences>
<preference>
<name>repository</name>
<value>repository</value>
<read-only>false</read-only>
</preference>
...
<preference>
<name>ShowTitle</name>
<value>false</value>
<read-only>false</read-only>
</preference>
</preferences>
</portlet>
<title>Introduce</title>
<access-permissions>Everyone</access-permissions>
<show-info-bar>false</show-info-bar>
<show-application-state>false</show-application-state>
<show-application-mode>false</show-application-mode>
</portlet-application>
</container>
</container>
</page>
This section is meant to help you organize the layout and structure of your portal. Review the "Working with applications" chapter to learn more about portlet configuration within the pages.xml file.
Navigation:
The navigation.xml is used to associate the links in your navigation (called page-node) with your portal pages.
If the pattern #{} is used then the label of the link will be loaded from the portal resource bundle (link to the ref guide about resource bundles
<?xml version="1.0" encoding="UTF-8"?>
<node-navigation>
<owner-type>portal</owner-type>
<owner-id>classic</owner-id>
<priority>1</priority>
<page-nodes>
<node>
<uri>home</uri>
<name>home</name>
<label>#{portal.classic.home}</label>
<page-reference>portal::classic::homepage</page-reference>
</node>
<node>
<uri>webexplorer</uri>
<name>webexplorer</name>
<label>#{portal.classic.webexplorer}</label>
<page-reference>portal::classic::webexplorer</page-reference>
</node>
</page-nodes>
</node-navigation>
This navigation tree can have multiple views inside portliest, such as breadcrumbs that render the current view node, the site map or the menu portlets.
For top nodes, the URI and the navigation node name must have the same value. For the other nodes, the URI is composed like <uri>contentmanagement/fileexplorer</uri> where 'contentmanagement' is the name of the parent node and 'fileexplorer' the name of the node (<name>fileexplorer</name>).
You can easily set the visibility of select pages and navigation to certain groups and users. Simply create pages.xml and navigation.xml files in folders named after the group and user to which you want to give permission:
sample-ext/portal/group/group-name/your files
sample-ext/portal/user/username/your files
One of the first steps in any web project is to integrate a graphic chart. This can be done entirely within your extension, by customizing the portal configuration.
In order to add a JavaScript library (for example JQuery), follow these steps:
Create the following folder, if it does not already exist: /war/src/main/webapp/WEB-INF/conf/script/groovy
Within this folder, create a JavascriptScript.groovy file
Add the following line to the groovy file
JavascriptService.addJavascript("Name_Of_Library", "/path_to/java_script/JavaScript_Lib.js", ServletContext);
For example:
JavascriptService.addJavascript("eXo.myproject.Jquery", "/javascript/eXo/myproject/jquery.js", ServletContext);
All languages are put in the myextension.war/WEB-INF/conf/common/locales-config.xml directory. Information of each language consists of key, output-encoding, input-encoding, description and orientation. Different languages will be defined in corresponding resource bundle file with keys specified in the locale-config.xml file. All languages defined in the locale-config.xml file will be listed in the Interface Language Settings.
To add a new language, you need to add the desired language node in the locale-config.xml file, then create a new resource bundle file containing the suffix name as key of the added node.
For example, to add Italian, do as follows:
Step 1: Add the following node to the locale-config.xml file.
<locale-config>
<locale>it</locale>
<output-encoding>UTF-8</output-encoding>
<input-encoding>UTF-8</input-encoding>
<description>Default configuration for Italian locale</description>
</locale-config>
Step 2: Create a new .properties file as webuien.properties in the portal.war/WEB-INF/classes/locale/portal folder.
This step is necessary because the Resource Bundle Service of the portal will find keys and values in the resource bundle file of each corresponding language.
Step 3: Restart the server.
To check if the added language takes effect, simply click the Change Language button on the top right corner of the portal. In the Interface Language Setting window, you will see the added Italian as shown:
Illustration 1: Italian display on Interface Language Setting
To remove an existing language, you need to delete the relevant language node in the locale-config.xml file and all files containing the suffix name as the key of language you want.
For example, to remove French, do as follows:
Step 1: Find and remove the following node from the locale-config.xml file.
<locale-config>
<locale>fr</locale>
<output-encoding>UTF-8</output-encoding>
<input-encoding>UTF-8</input-encoding>
<description>Default configuration for france locale</description>
</locale-config>
Step 2: Continue removing all resource bundle files containing the suffix name as fr in all folders.
It is recommended to do this step to delete unnecessary data in the application.
Step 3: Restart the server.
To check if the removed language takes effect, simply click the Change Language button on the top right corner of the portal. In the Interface Language Setting window, French as shown on Illustration 1 has not existed on the Interface Language Setting window.
Illustration 2: Interface Language Setting without French =======
The complete skinning of a page can be decomposed into three main parts:
Portal Skin
The portal skin contains the styles for html tags (ex div,th,td...) and the portal UI (including the toobar). This should include all the UI components except for the window decorators and portlet specific styles.
Window Styles
The CSS styles associated with the porlet window decorators. The window decorators contain the control buttons and borders surrounding each portlet. Individual portlets can have their own window decorator selected, or be rendered without one.
Portlet Skins
The portlet skins effect how portlets are rendered on the page. There are two main ways this can be affected:
Portlet Specification CSS Classes
The portlet specification defines a set of css classes that should be available to portlets. Platform provides these classes as part of the portal skin. This allows each portal skin to define its own look and feel for these default values.
Portlet Skins
Platform provides a means for portlet CSS files to be loaded based on the current portal skin. This allows a portlet to provide different CSS styles to better match the current portal look and feel.
The window decorators and the default portlet specification CSS classes should be considered separate types of skinning components, but they need to be included as part of the overall portal skin. The portal skin must include these component's CSS classes or they will not be displayed correctly. A portlet skin doesn't need to be included as part of the portal skin and can be included within the portlets web application.
The skin folder structure must be prepared as soon as you start the design. Follow these conventions and best practices to ease the integration of your design in Platform.
The id and class names are named after the WebUI components name and portlets name with the 'UI-'as prefix. The same rule is applied for folder that contains the components and portlets. It will help you find and edit the correct files easily. ie: UI portlet will be named like: UIFooterPortlet, UIBannerPortlet,etc UI component will be named like: UIToolbarContainer, UIVerticalTab, etc
Portal skin The portal skin will appear as a single link to a CSS file. This link will contain contents from all the portal skin classes merged into one file. This allows the portal skin to be transfered more quickly as a single file instead of many smaller files included with every page render.
The general folder structure for portal skin:
/webapp/skin/NameOfPortalSkin/portal
ie:
/webapp/skin/DefaultSkin/portal
The main entry CSS file:
The main entry CSS file hould be placed right in the main portal skin folder.The file is the main entry point to the CSS class definitions for the skin:
/webapp/skin/NameOfPortalSkin/Stylesheet.css
ie :
/webapp/skin/SkinBlue/Stylesheet.css
The folder structure for WebUI components:
/webapp/skin/SkinBlue/webui/component/YourUIComponentName
ie:
/webapp/skin/SkinBlue/webui/component/UIToolbarContainer
Window decorator CSS is put in:
webapp/skin/PortletThemes/Stylesheet.css
Where to put images for portal skin?
The images for portal skin should be put in the background foler right in the Portal skin folder and for each UI component.
ie:
/webapp/skin/SkinBlue/webui/component/UIProfileUser/SkinBlue/background
In summary, the folder structure for a new portal skin should be:
webapp
skin
NameOfPortalSkin
stylesheet.css
webui
component
UIComponentName
NameOfPortalSkin.css
NameOfPortalSkin
background
ie:
webapp
skin
DefaultSkin
stylesheet.css
webui
UISpaceSearch
DefaultSkin.css
DefaultSkin
background
Portlet skin
Each portlet on a page may contribute its own style. The link to the portlet skin will only appear on the page if that portlet is loaded on the current page. A page may contain many portlet skin CSS links or none. The link ID will be named like . For example: ContentPortlet in content.war, will give id="contentContentPortlet"
The general folder structure for portlet skin:
/webapp/skin/portlet/webui/component/YourUIPortletName
and for groovy skin: /webapp/groovy/portlet/webui/component/YourUIPortletName/
ie:
/webapp/skin/portlet/webui/component/UIBannerPortlet
/webapp/groovy/portlet/webui/component/UIBannerPortlet
Portlet images folder:
/webapp/skin/portlet/YourUIPortletName/PortalSkinName/background
ie:
/webapp/skin/portlet/UIBannerPortlet/BlueSkin/background
Portlet themes
Main entry css:/webapp/skin/PortletThemes/Stylesheet.css
/webapp/skin/PortletThemes/background
/webapp/skin/PortletThemes/icons
GateIn 3.1 provides support for skinning the entire User Interface (UI) of portal, including all common portal elements, custom skins and window decorator for individual portlets. Skins are designed to help you pack and reuse common graphic resources.
The default skin can be set in the portal configuration files. The skin configured as default is used by GateIn as the administrator starts/restarts the server. To change the default skin, add a skin tag to the portal.war/WEB-INF/conf/portal/portal/classic/portal.xml configuration file. To change the skin to MySkin, do as follows:
<portal-config>
<portal-name>classic</portal-name>
<locale>en</locale>
<access-permissions>Everyone</access-permissions>
<edit-permission>*:/platform/administrators</edit-permission>
<skin>MySkin</skin>
...
The GateIn 3.1 skin not only contains CSS styles for the portal's components, but also shares components that may be reused in portlets. When GateIn 3.1 generates the page markup of portal, it inserts stylesheet links in the page's head tag. There are two main types of CSS links which appear in the head tag: one to the portal skin CSS file and the other to the portlet skin CSS file.
Portal Skin appears as a single link to a CSS file. This link contains contents from all portal skin classes merged into one file. The portal skin will be transfered more quickly as a single file instead of multiple smaller files.
Portlet Skin only appears as the link on the page if that portlet is loaded on the current page. A page may contain many CSS links of portlet skins or none.
In the code fragment below, you can see two types of links:
<head> ... <!-- The portal skin --> <link id="CoreSkin" rel="stylesheet" type="text/css" href="/eXoResources/skin/Stylesheet.css" /> <!-- The portlet skins --> <link id="web_FooterPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/ component/UIFooterPortlet/DefaultStylesheet.css" /> <link id="web_NavigationPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/ component/UINavigationPortlet/DefaultStylesheet.css" /> <link id="web_HomePagePortlet" rel="stylesheet" type="text/css" href= "/portal/templates/skin/ webui/component/UIHomePagePortlet/DefaultStylesheet.css" /> <link id="web_BannerPortlet" rel="stylesheet" type="text/css" href= "/web/skin/portal/webui/ component/UIBannerPortlet/DefaultStylesheet.css" /> ... </head>
Window styles and portlet specification CSS classes are included within the portal skin.
SkinService in GateIn 3.1 is to manage various types of skins. It is used to discover and deploy skins into the portal.
GateIn 3.1 automatically discovers web archives that contain a file descriptor for skins (WEB-INF/gatein-resources.xml). This file is to specify which portal, portlet and window decorators will be deployed into the skin service. The full schema can be found in the lib directory: exo.portal.component.portal.jar/gateinresources10.xsd. Here is an example where we define a skin (MySkin) with its CSS location, and specify a few window decorator skins:
<gatein-resources>
<portal-skin>
<skin-name>MySkin</skin-name>
<css-path>/skin/myskin.css</css-path>
<overwrite>false</overwrite>
</portal-skin>
<!-- window style -->
<window-style>
<style-name>MyThemeCategory</style-name>
<style-theme>
<theme-name>MyThemeBlue</theme-name>
</style-theme>
<style-theme>
<theme-name>MyThemeRed</theme-name>
</style-theme>
</window-style>
</gatein-resources>
With the Right-To-Left support, you need to retrieve all CSS files through a Servlet filter and to configure the web application to activate this filter. This has been already done for the eXoResources.war web application which contains the default skin. Any new web applications containing skinning CSS files need to have the following added to their web.xml:
<filter>
<filter-name>ResourceRequestFilter</filter-name>
<filter-class>org.exoplatform.portal.application.ResourceRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ResourceRequestFilter</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
The configuration of Portlet Skin takes an optional parameter application-name, which is the web application wrapping skinned portlet. Hence, the display-name element in web.xml need to be coherent with the application-name in the gatein-resources.xml file.
<portlet-skin> <!-- the application-name must be identical to display-name of the web application wrapping HomePagePortlet portlet --> <application-name>web</application-name> <portlet-name>HomePagePortlet</portlet-name> <skin-name>Default</skin-name> <css-path>/templates/skin/webui/component/UIHomePagePortlet/DefaultStylesheet.css</css-path> </portlet-skin>
The default skin of GateIn 3.1 is located as part of the eXoResource.war. The main files associated with the skin include:
WEB-INF/gatein-resources.xml: defines the skin settings to use.
WEB-INF/web.xml: contains the resource filter with the display-name set.
skin/Stylesheet.css: contains the CSS class definitions for this skin.
The following block of CSS illustrates content of the Stylesheet.css file:
@import url(DefaultSkin/portal/webui/component/UIPortalApplicationSkin.css); (1) @import url(DefaultSkin/webui/component/Stylesheet.css); (2) @import url(PortletThemes/Stylesheet.css); (3) @import url(Portlet/Stylesheet.css); (4)
In which, (1) Skin of portal page. UIPortalApplicationSkin.css defines CSS classes shared by all the portal pages. (2) Skins of various portal-owned components, such as WorkingWorkspace, MaskWorkspace, PortalForm, and more. (3) Window decorator skins. (4) The portlet specification CSS classes. (The CSS styles defined in Portlet Specification JSR286)
To make a default skin flexible and highly reusable, instead of defining all CSS classes in this file, CSS classes are arranged in nested stylesheet files, based on the @import statement. This makes easier for new skins to reuse parts of the default skin. To reuse a CSS stylesheet from the default portal skin, you need to refer to the default skin from eXoResources. For example, to include the window decorators from the default skin within a new portal skin, you need to use the following import:
@import url(/eXoResources/skin/Portlet/Stylesheet.css);
When the portal skin is added to the page, it merges all CSS stylesheets into a single file.
It is required to add a new skin to the portal through the skin service. Web applications containing the skin need to be properly configured for the skin service to discover them, meaning that the gatein-resources.xml must be configured correctly.
You need to specify the new portal skin in the gatein-resources.xml file. You also need to specify the name of new skin, where to locate its CSS stylesheet file and whether to overwrite the existing portal theme with the same name.
<gatein-resources> <portal-skin> <skin-name>MySkin</skin-name> <css-path>/skin/myskin.css</css-path> <overwrite>false</overwrite> </portal-skin> </gatein-resources>
The default portal skin and window styles are defined in the eXoResources.war/WEB-INF/gatein-resources.xml.
The CSS for the portal skin needs to contain CSS for all window decorators and portlet specification CSS classes.
You can preview the appearance of portal skin when selecting it. To display the preview image of deployed skins, the current skin must be aware of all those icons. Hence, each skin must contain preview images of all other skins.
For any portal skin, the paths to preview images are specified in CSS class UIChangeSkinForm:
eXoResources/src/main/webapp/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/Stylesheet.css
For the portal named MySkin, it is required to define the following CSS classes:
.UIChangeSkinForm .UIItemSelector .TemplateContainer .MySkinImage
The default skin would be aware of skin icons if the preview screenshot is placed in: eXoResources.war:/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/background.
The CSS stylesheet for the default portal needs to have the following updated with the preview icon CSS class. For the skin named MySkin, it is required to update the following: eXoResources.war:/skin/DefaultSkin/portal/webui/component/customization/UIChangeSkinForm/Stylesheet.css. For now, amending deployed package eXoResources is inevitable (modifying default war/jar breaches development convention of GateIn-based products). The problem would be resolved in future GateIn versions in which different skin modules are fully independent, for example, there will be no preview image duplication.
UIChangeSkinForm .UIItemSelector .TemplateContainer .MySkinImage {
margin: auto;
width: 329px; height:204px;
background: url('background/MySkin.jpg') no-repeat top;
cursor: pointer ;
}
Window style is the CSS applied to the window decorator. When the administrator selects a new application to add to a page, he can decide which style of decorator surrounding the window if any.
Window style is defined within the gatein-resources.xml file used by the SkinService to deploy the window style into the portal. Window styles can belong to a window style category. This category and window styles need to be specified in the resources file. The following gatein-resource.xml fragment will add MyThemeBlue and MyThemeRed to the MyTheme category.
<window-style> <style-name>MyTheme</style-name> <style-theme> <theme-name>MyThemeBlue</theme-name> </style-theme> <style-theme> <theme-name>MyThemeRed</theme-name> </style-theme> </window-style>
The windows style of the default skin is configured in the eXoResources.war/WEB-INF/gatein-resources.xml file.
When a window style is defined in the gatein-resources.xml file, it will be available to all portlets regardless of whether the current portal skin supports the window decorator or not. When a new window decorator is added, it should be added to all portal skins or the portal skins should share a common stylesheet for window decorators.
In order for the SkinService to display the window decorators, it must have CSS classes with the specific naming related to the window style name. The service will try and display CSS based on this naming. The CSS class must be included as part of the current portal skin for the window decorators to be displayed. The window decorator CSS classes for the default portal theme are located at: eXoResources.war/skin/PortletThemes/Stylesheet.css
Portlets often require additional styles that may not be defined by the portal skin. GateIn 3.1 defines additional stylesheets for each portlet and will append the corresponding link tags to the head. The ID attribute of <link> element will be in the form portletAppNamePortletName. For example, the ContentPortlet in content.war takes "content/ContentPortlet" as ID. To define a new CSS file to be included whenever a portlet is available on a portal page, the following fragment needs to be added in the gatein-resources.xml file.
<portlet-skin> <application-name>portletAppName</application-name> <portlet-name>PortletName</portlet-name> <skin-name>Default</skin-name> <css-path>/skin/DefaultStylesheet.css</css-path> </portlet-skin> <portlet-skin> <application-name>portletAppName</application-name> <portlet-name>PortletName</portlet-name> <skin-name>OtherSkin</skin-name> <css-path>/skin/OtherSkinStylesheet.css</css-path> </portlet-skin>
This action will load DefaultStylesheet.css or OtherSkinStylesheet.css when the DefaultSkin or OtherSkin is used respectively.
If the current portal skin is not defined as part of the supported skins, the portlet CSS class will not be loaded. The portlet skins should be updated whenever a new portal skin is created.
Each portlet can be represented by an unique icon that you can see in the portlet registry or page editor. This icon can be changed by adding an image to the directory of portlet web application: skin/DefaultSkin/portletIcons/iconname.png. The icon must be named after the portlet. For example, the icon of account portlet must be named AccountPortlet and located at: skin/DefaultSkin/portletIcons/AccountPortlet.png
You must use skin/DefaultSkin/portletIcons/ for the directory to store the portlet icon regardless of using any skins.
The SkinService handles stylesheet rewriting to accommodate the orientation. It works by appending -lt or -rt to the stylesheet name. For instance, /web/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet-rt.css will return the same stylesheet as /web/skin/portal/webui/component/UIFooterPortlet/DefaultStylesheet.css but processed for the RT orientation. The -lt suffix is optional. Stylesheet authors can annotate their stylesheet to create content that depends on the orientation.
Example 1. In this example, we need to use the orientation to modify the float attribute that will make the horizontal tabs either float on left or on right:
float: left; /* orientation=lt */ float: right; /* orientation=rt */ font-weight: bold; text-align: center; white-space: nowrap;
The LT produced output will be:
float: left; /* orientation=lt */ font-weight: bold; text-align: center; white-space: nowrap;
The RT produced output will be:
float: right; /* orientation=rt */ font-weight: bold; text-align: center; white-space: nowrap;
Example 2. In this example, we need to modify the padding based on the orientation:
color: white; line-height: 24px; padding: 0px 5px 0px 0px; /* orientation=lt */ padding: 0px 0px 0px 5px; /* orientation=rt */
The LT produced output will be:
color: white; line-height: 24px; padding: 0px 5px 0px 0px; /* orientation=lt */
The RT produced output will be:
color: white; line-height: 24px; padding: 0px 0px 0px 5px; /* orientation=rt */
The extension mechanism of GateIn 3.1 enables the skin definition to be replaced with the skin resource configured in the extension-deployed web application. This is the example where the CSS path of default portal skin needs to be modified without touching the GateIn's files.
<gatein-resources> <portal-skin> <skin-name>MySkin</skin-name> <css-path>/skin/myskin.css</css-path> <overwrite>false</overwrite> </portal-skin> </gatein-resources>
To do so, do as follows:
Step 1: Create a web application whose gatein-resources.xml contains the same content as the above xml block, except the element <css-path> is modified.
Step 2: Register the artifact in the dependencies list of extended Portal Container.
Step 3: Ensure that once the server has deployed the artifact, it does not load any web application with gatein-resources.xml configuring the same portal skin.
By the time those lines are written out, the control of loading order required in the third step relies totally on the Web Container Integration (WCI), hence the conflict may occur. That would be resolved by the concept of portal skin priority introduced in the coming version of GateIn.
This tutorial will help you to create a new layout and skin, and give some best practices you should know and respect when creating a new layout and skin for your portal and page.
You have an extension named "MyPortal", and you need to create a site called "MySite" inside this portal.
The <myportal_path> below is replaced by the based path of your "MyPortal" extension.
If you see any folder/file which does not exist, you should create a new one.
This section is related to the configuration. You can see a sample here. You can leave all the portlet's preferences as blank, that means the default value will be taken and you do not need to care about it at this time.
For example, you will have a layout like this:
In which:
Branding: A branding application
Top navigation: A top navigation application
A table column container with three nested containers:
Left Column and Right Column: contain one application for each.
Main content: contains the page body.
And here is the "short version" of
portal.xml
.
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/portal/portal/mysite/portal.xml
<!-- ... -->
<portlet-application>
<!-- Branding application. You can use WCM web content *exo:webContent* for the content and SCV portlet to display -->
</portlet-application>
<portlet-application>
<!-- navigation application. You can use WCM web content *exo:webContent* for the content and SCV portlet to display -->
</portlet-application>
<container id="MySite" template="system:/groovy/portal/webui/container/UITableColumnContainer.gtmpl">
<container id="LeftColumn" template="system:/groovy/portal/webui/container/UIContainer.gtmpl">
<!-- One or more application(s) here -->
<portlet-application>
</portlet-application>
</container>
<container template="system:/groovy/portal/webui/container/UIContainer.gtmpl">
<page-body>
</page-body>
</container>
<container id="RightColumn" template="system:/groovy/portal/webui/container/UIContainer.gtmpl">
<!-- One or more application(s) here -->
<portlet-application>
</portlet-application>
</container>
</container>
<portlet-application>
<!-- Footer application. You can use WCM web content *exo:webContent* for the content and SCV portlet to display -->
</portlet-application>
<!-- ... -->
As you see in the portal.xml file above, every container tag has an id attribute, for example "<container id = 'RightColumn'>". When you create a CSS file, the property applied for this container should have the following name manner:
${container_id}TDContainer
and the details of this container:
RightColumnTDContainer
The reason is, when you have a look in the file system:/groovy/portal/webui/container/UITableColumnContainer.gtmpl_* shown above, you will see this code fragment:
<table class="UITableColumnContainer" style="table-layout: fixed; margin: 0px auto; $style">
<tr class="TRContainer">
<% for(uiChild in uicomponent.getChildren()) {%>
<td class="${uiChild.id}TDContainer TDContainer"><% uicomponent.renderUIComponent(uiChild) %></td>
<% } %>
</tr>
</table>
So, in the table element (which represents the outer container), there are many td elements, each of which has the class attribute that equals to the id of the corresponding child component plus the "TDContainer" string literal.
To learn more, see Customize portal and page's style.
This section is related to the configuration. You can see a sample here. You can leave all the portlet's preferences as blank, that means the default value will be taken and you do not need to care about it at this time.
Like
portal.xml
, you can define the layout for each page in your site as shown in the following example:
<!-- ... -->
<portlet-application>
<!-- A custom document for content and SCV portlet to display -->
</portlet-application>
<portlet-application>
<!-- A CLV portlet with a custom template. -->
</portlet-application>
<portlet-application>
<!-- A CLV portlet with another custom template. -->
</portlet-application>
<!-- ... -->
If you want your skin to be applied for every page, do as follows:
Step 1: Go to Sites Explorer portlet > Shared drive > CSS folder.
Step 2: Create a new CSS document which contains your stylesheet. You can use any name for this document and put a priority number.
If you want your skin to be applied for your MySite page only, do as follows:
Step 1: Open the browser > Sites Explorer portlet > Sites management drive > MySite/css folder.
Step 2: Create a new CSS document which contains your stylesheet for the portal and the page layout. You can use any name for this document and put a priority number.
This document should contain ONLY the stylesheet for the page and portal level.
The following is one sample stylesheet:
/* ... */
.LeftColumnTDContainer {
/* ... */
}
.RightColumnTDContainer {
/* ... */
}
/* ... */
The order of applying CSS files (of site and web content) depends on their own priority property value. It means that we can apply the site CSS first and then web content CSS, or vice versa.
This section is related to the configuration. You can see a sample here
Apply your HTML/Groovy template code for this template. For example:
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/template/list/ACustomizedCLVTemplate.gtmpl
<div id="$uicomponent.id" class="ACustomizedCLVTemplate">
<div class="ListContents">
<!-- something here -->
</div>
</div>
Now, we need to import this template to the database.
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/template/configuration.xml
<external-component-plugins>
<target-component>org.exoplatform.services.cms.views.ApplicationTemplateManagerService</target-component>
<component-plugin>
<name>ACustomizedCLVTemplate</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.cms.views.PortletTemplatePlugin</type>
<description>This is a sample customized CLV template</description>
<init-params>
<value-param>
<name>portletName</name>
<value>Content List Viewer</value>
</value-param>
<value-param>
<name>portlet.template.path</name>
<value>war:/conf/myportal/customized/template</value>
</value-param>
<object-param>
<name>default.folder.list.viewer</name>
<description>Default folder list viewer groovy template</description>
<object type="org.exoplatform.services.cms.views.PortletTemplatePlugin$PortletTemplateConfig">
<field name="templateName">
<string>ACustomizedCLVTemplate.gtmpl</string>
</field>
<field name="category">
<string>list</string>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
To customize CLV template's style, do as follows:
Step 1: Go to Sites explorer portlet > Sites management drive > MySite/css folder.
Step 2: Create a new CSS document which contains your stylesheet for the portal and the page layout. You can use any name for this document and put a priority number.
This document should contain ONLY the stylesheet for THIS template. If you have another template, you should create a new CSS document.
The following is one sample stylesheet:
/* ... */
.ACustomizedCLVTemplate {
/* ... */
}
.ListContents {
/* ... */
}
/* ... */
Step 3: Export the document and now you have an XML file.
Please check out this tutorial to know how to import this XML into database.
This section is related to the configuration. You can see a sample here.
- First, you need to create a new document definition.
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/document/ACustomizedDocument.xml
node type name :exo:customizedDocument properties: exo:name(type : String), exo:title(type : String), exo:content(type : String)
You also need to configure it to make sure it is imported to the database.
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/document/definition-configuration.xml
<external-component-plugins>
<target-component>org.exoplatform.services.jcr.RepositoryService</target-component>
<component-plugin>
<name>ACustomizedDocument</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.jcr.impl.AddNodeTypePlugin</type>
<priority>200</priority>
<init-params>
<values-param>
<name>autoCreatedInNewRepository</name>
<description>ACustomizedDocument document definition</description>
<value>war:/conf/myportal/customized/document/ACustomizedDocument.xml</value>
</values-param>
</init-params>
</component-plugin>
</external-component-plugins>
Now it is time to create the templates for this document, including:
Dialog: see the sample here)
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/document/dialog.gtmpl
<div class="UIForm ACustomizedDocument">
<% uiform.begin() %>
<!-- Document dialog content is here -->
<% uiform.end() %>
View: see the sample here)
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/document/view.gtmpl
<style>
<% _ctx.include(uicomponent.getTemplateSkin("exo:customizedDocument", "Stylesheet")); %>
</style>
<!-- Document view template content is here -->
Stylesheet: see the sample here)
This document should contain ONLY the stylesheet for THIS template.
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/document/stylesheet.css
/* ... */
.ACustomizedDocument {
/* ... */
}
/* ... */
You also need to import them to database.
<myportalpath>/src/main/webapp/WEB-INF/conf/myportal/customized/document/template-configuration.xml
<external-component-plugins>
<target-component>org.exoplatform.services.cms.templates.TemplateService</target-component>
<component-plugin>
<name>addTemplates</name>
<set-method>addTemplates</set-method>
<type>org.exoplatform.services.cms.templates.impl.TemplatePlugin</type>
<init-params>
<value-param>
<name>autoCreateInNewRepository</name>
<value>true</value>
</value-param>
<value-param>
<name>storedLocation</name>
<value>war:/conf/myportal/customized/document</value>
</value-param>
<value-param>
<name>repository</name>
<value>repository</value>
</value-param>
<object-param>
<name>template.configuration</name>
<description>configuration for the localtion of nodetypes templates to inject in jcr</description>
<object type="org.exoplatform.services.cms.templates.impl.TemplateConfig">
<field name="nodeTypes">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$NodeType">
<field name="nodetypeName">
<string>exo:customizedDocument</string>
</field>
<field name="documentTemplate">
<boolean>true</boolean>
</field>
<field name="label">
<string>Customized Document</string>
</field>
<field name="referencedView">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$Template">
<field name="templateFile">
<string>view.gtmpl</string>
</field>
<field name="roles">
<string>*</string>
</field>
</object>
</value>
</collection>
</field>
<field name="referencedDialog">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$Template">
<field name="templateFile">
<string>dialog.gtmpl</string>
</field>
<field name="roles">
<string>webdesigner:/platform/web-contributors</string>
</field>
</object>
</value>
</collection>
</field>
<field name="referencedSkin">
<collection type="java.util.ArrayList">
<value>
<object type="org.exoplatform.services.cms.templates.impl.TemplateConfig$Template">
<field name="templateFile">
<string>stylesheet.css</string>
</field>
<field name="roles">
<string>*</string>
</field>
</object>
</value>
</collection>
</field>
</object>
</value>
</collection>
</field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>
Finally, you should create some initial contents and export them to XML files.
To import this XML into database, you can set up for the deployment like this:
<external-component-plugins>
<target-component>org.exoplatform.services.wcm.deployment.WCMContentInitializerService</target-component>
<component-plugin>
<name>Content Initializer Service</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.wcm.deployment.plugins.XMLDeploymentPlugin</type>
<description>XML Deployment Plugin</description>
<init-params>
<object-param>
<name>ACME Logo data</name>
<description>Deployment Descriptor</description>
<object type="org.exoplatform.services.deployment.DeploymentDescriptor">
<field name="target">
<object type="org.exoplatform.services.deployment.DeploymentDescriptor$Target">
<field name="repository"><string>repository</string></field>
<field name="workspace"><string>collaboration</string></field>
<field name="nodePath"><string>/sites content/live/acme/web contents/site artifacts</string></field>
</object>
</field>
<field name="sourcePath"><string>war:/conf/wcm/artifacts/site-resources/acme/Logo.xml</string></field>
</object>
</object-param>
</init-params>
</component-plugin>
</external-component-plugins>