Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

53
Developing themes and skins in IBM® WebSphere® Portal 6.0.X Ryan Wilson WebSphere Portal Level 2 Support, WPLC.J2EE/Portal/WebSphere-based technology Durham, NC Jim Barnes WebSphere Portal Level 2 API Team Lead, WPLC.J2EE/Portal/WebSphere-based technology Durham, NC March 2008 © Copyright International Business Machines Corporation 2008. All rights reserved. This document provides IBM® WebSphere® Portal developers an understanding of the new features and layouts available with the version 6.0.X themes and skins, addressing new functionality such as theme extensions and theme policies. It also covers how the various files that make up the complete theme are pulled together and how they are used to control the various aspects of the look and feel. To get the most from this white paper, you should be familiar with Java™ Server Page (JSP) and servlet development practices, WebSphere Portal concepts such as xmlaccess, and WebSphere Application Server administration. Moreover, you should be well versed in HTML and cascading stylesheet (CSS) files since the WebSphere Portal themes and skins are returned to the browser in HTML. Table of contents 1 Introduction..................................................................................................................................3 2 Themes and skins basics ..............................................................................................................3 2.1 JSP files for themes........................................................................................................................... 4 2.2 JSP files for portlet layout and rendering ...................................................................................... 5 2.3 JSP files used for stylesheets ............................................................................................................ 6 2.4 JSP files used for JavaScript ........................................................................................................... 6 2.5 Additional JSP files used by the portal theme ............................................................................... 7 2.6 Tags used by WebSphere Portal JSPs ............................................................................................ 8 3 Theme policy ..............................................................................................................................11 3.1 Exporting and updating a theme policy........................................................................................ 13

Transcript of Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Page 1: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Developing themes and skins in IBM® WebSphere® Portal 6.0.X Ryan WilsonWebSphere Portal Level 2 Support, WPLC.J2EE/Portal/WebSphere-based technology Durham, NC Jim BarnesWebSphere Portal Level 2 API Team Lead, WPLC.J2EE/Portal/WebSphere-based technology Durham, NC March 2008 © Copyright International Business Machines Corporation 2008. All rights reserved. This document provides IBM® WebSphere® Portal developers an understanding of the new features and layouts available with the version 6.0.X themes and skins, addressing new functionality such as theme extensions and theme policies. It also covers how the various files that make up the complete theme are pulled together and how they are used to control the various aspects of the look and feel. To get the most from this white paper, you should be familiar with Java™ Server Page (JSP) and servlet development practices, WebSphere Portal concepts such as xmlaccess, and WebSphere Application Server administration. Moreover, you should be well versed in HTML and cascading stylesheet (CSS) files since the WebSphere Portal themes and skins are returned to the browser in HTML. Table of contents1 Introduction..................................................................................................................................3

2 Themes and skins basics ..............................................................................................................3 2.1 JSP files for themes........................................................................................................................... 4

2.2 JSP files for portlet layout and rendering ...................................................................................... 5

2.3 JSP files used for stylesheets............................................................................................................ 6

2.4 JSP files used for JavaScript ........................................................................................................... 6

2.5 Additional JSP files used by the portal theme ............................................................................... 7

2.6 Tags used by WebSphere Portal JSPs ............................................................................................ 8

3 Theme policy ..............................................................................................................................11 3.1 Exporting and updating a theme policy........................................................................................ 13

Page 2: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

3.2 Adding custom policy attributes.................................................................................................... 15

3.3 Accessing standard theme policy attributes ................................................................................. 17

4 Color palette ...............................................................................................................................18 4.1 Creating the palette ........................................................................................................................ 18

4.2 Assigning the palette to a page ...................................................................................................... 19

5 Theme extensions.......................................................................................................................20

6 Flyouts and context menus .......................................................................................................32 6.1 Flyouts ............................................................................................................................................. 32

6.2 Context menus................................................................................................................................ 34

7 Development tools .....................................................................................................................37

8 Migrating to version 6.0 from version 5.1................................................................................39 8.1 Adding drag and drop.................................................................................................................... 39

8.2 Considerations when migrating.................................................................................................... 43

9 Conclusion.................................................................................................................................44

Appendix A: Drop-down navigation example ..........................................................................45

Appendix C: Removing unwanted space......................................................................................48

Appendix D: Changing properties of the flyout...........................................................................49

Resources.......................................................................................................................................52

About the authors..........................................................................................................................52

Acknowledgements........................................................................................................................52

Page 3: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

1 Introduction This document is a comprehensive treatment of all aspects of developing themes and skins for WebSphere Portal 6.0, including theme policy, color palette, theme extensions, and flyouts and context menus. We also explain how to migrate themes and skins from version 6.0 from 5.1.

2 Themes and skins basics Before you start coding your new custom theme and skin, you need to understand how all the parts of the version 6.0 themes fit together. If this is the first time you will be customizing themes for WebSphere Portal, you may get confused by what each JSP and JSPF will do for the overall portal and what is appropriate to add to a JSP.

NOTE: Avoid customizing the theme provided out-of-the-box. It is best practice to copy the IBM directory, give it your own name, and then use that for your sample. Also, it is best to assign it to a page only, and not the whole portal, while developing it.

In this white paper we include a theme and a skin that give you the same theme and skin as shown above in your own portal environment. This process is best done on a stand-alone test environment and is not intended for a clustered configuration. To install, simply extract the .zip files, using a .zip utility or the .jar command, into the following locations: For themes: profiles/wp_profile/installedApps/nodename/wps.ear/wps.war/themes/html/ For skins:

profiles/wp_profile/installedApps/nodename/wps.ear/wps.war/skins/html/

Use the supplied XML file (install_whitepaper.xml) to install the themes and skins and sample pages into your portal. This installation creates a tab labeled White Paper, with pages under it with several example themes and skins to go along with the white paper (see figure 1).

Page 4: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Figure 1. White Paper tab

After the installation is complete, open the page in your browser to display the screen in figure 1 above. (Note that this sample is best viewed with the Firefox browser.) This page lets you see what part of the overall markup is coming from which JSPs. You are also able to see how they all fit together on the page to make one finished HTML document. Consider that the theme controls the look and feel of your portal and the navigation throughout the site. The rest of the layout of the portal page, which includes how the portlets exist relative to each other, is controlled by the default skin for that theme. The look and feel of the portlet itself is controlled by the skin you have configured for that portlet. If no skin is configured, the portlet renders the default skin. If you select a skin for a portlet, not all of its JSPs are called; only the control.jsp file is called for that skin to render that portlet. This limitation allows these files to change their rendering based on any theme extensions.

2.1 JSP files for themes Default.jsp. This file is the JSP that renders the portal page after the portal servlet has completed its initial preprocessing. This JSP includes numerous other JSPs, JSPFs, and tag lib definitions. The file also calls the js.jsp and the styles.jsp files, so that they are compiled, and so the styles and JavaScripts can include JSP logic to change the behavior of the portal dynamically. Head.jspf. This fragment is called to set up the header area of the page. Theme extensions implementing the MetaTagDataItems are included at this time. Several JNDI lookup operations are performed in this JSPF file. The file also sets up links to the JavaScript and styles JSP files. Additionally it sets up some of the resources needed for the flyouts and gets other variables ready for the main menu (Launch button).

Page 5: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Banner.jspf. This fragment is the first visible JSP fragment to be included in the portal. It represents the top layer of the page and it holds the launch button, the breadcrumb trail, the search control, and the toolbar JSPF files.

TopNav.jspf. This fragment controls the look and feel of the top navigational bar. This bar can be one or two layers, depending on the theme policy selected. Edit this JSP file if you want to create a drop-down navigational structure. The file also holds logic to render the context menus for the page. Appendixes A and B show additional variations on the navigation of the WebSphere Portal site. SideNav.jspf. This fragment controls the side navigation and only has visible content if needed. This page also has logic to expand and contract the child pages and build the context menus for the pages. Footer.jspf. The final fragment is the footer, which holds the normal footer information for page navigation and quick links to other pages for the users.

2.2 JSP files for portlet layout and rendering The container JSP files are called from the default skin so they can lay the portlets in columns and rows. The skin selected for the portlet does not affect the stacking of the portlets into columns or rows. It is always the default skin for the theme that holds the container JSP files, which in turn control the layout of rows and columns. If the default skin does not contain the JSP unlayered containers as listed below, then the aggregation engine pulls them from the base skin/html directory:

UnlayeredContainer-V.jsp. This file controls the vertical columns for the portlets and how they are arranged within that column. The tags in the JSP file help control the drag-and-drop feature.

UnlayeredContainer-H.jsp. This file controls the horizontal appearance of the portlets and can contain the UnlayeredContainer-V.jsp.

Control.jsp. This file controls the look and feel of the portlet itself. It renders the menu items, the title bar, and the table that holds the portlet content. It also provides drag-and-drop handles for moving the portlet around on the portlet page.

These files contain references back to the theme to maintain the same look and feel, which include images and colors. The files that are containers (UnlayeredContainer-V.jsp and UnlayeredContainer-H.jsp) are used to render the rows and columns. In figure 1 above, for example, you can see that there is one row, rendered by UnlayeredContainer-H.jsp with two columns, with both being rendered by UnlayeredContainer-V.jsp. These rows and columns correspond to the layout from the edit layout page of the administration portlet. So, for each column or row, you have separate rendering of the above files.

Page 6: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

2.3 JSP files used for stylesheets In WebSphere Portal version 6.0, there is one JSP file that is called, and it’s compiled based on various items from the request, theme policy, and color palette:

Styles.jsp – This is the main JSP file that is called when included in the theme. It is empty of any real content and includes the following JSPF files: styles_cacheSettings.jspf, styles_rules.jspf, styles_theme.jspf, styles_portlet.jspf, styles_help.jspf, styles_oob.jspf, styles_ibm.jspf, styles_palette.jspf, and styles_extensions.jspf. Appendix C shows just one way that the styles can be adjusted to affect the layout of the theme. The JSPF files control the style declarations for the following pieces:

styles_cacheSettings.jspf – declares how long the CSS files should be cached. This file is used to improve performance on the browser side so that it doesn’t need to constantly request this resource.

styles_extensions.jspf – loops through and pulls any theme extension pieces styles.

styles_help.jspf – styles for help related text and controls.

styles_ibm.jspf – styles used for admin portlets, which generally should not be changed.

styles_oob.jspf – styles for portlets and controls that are ready to use, as is.

styles_palette.jspf – styles used for the palettes and drop-down controls.

styles_portlet.jspf – styles used for portlets that follow the Web Services for Remote Portlets (WSRP) portlet standard.

styles_rules.jspf – styles used for browser and locale-specific CSS files. All CSS JSP files should include this one file.

styles_theme.jspf – styles used in the base theme and in the drag-and-drop tags.

2.4 JSP files used for JavaScript The themes and skins in WebSphere Portal 6.0 make extensive use of JavaScript. When adding your own JavaScript, ensure there are no collisions with the already-existing JavaScript in the theme. Like the other parts of WebSphere Portal, there is one main JavaScript file that includes several other JavaScript files:

js.jsp. This JSP file includes the files js_cacheSettings.jspf, AsynchronousContextMenu.js, browserDimensions.js, ElementJavascriptEventController.js, flyout.js, and js_extensions.jspf, which are defined as follows:

js_cacheSettings.jspf – similar to the cache settings file for stylesheets, this file allows the JavaScript files to be cached by the browser instead of requiring it to be reloaded on every request.

AsynchronousContextMenu.js – used for the context menus that WebSphere Portal renders (such as from the portlet drop-down and the theme drop-down controls.) This file should not be modified.

browserDimensions.js – determines the browser window size for such elements as flyouts.

ElementJavascriptEventController.js – contains helper methods for the other JavaScript files that should not be modified.

Page 7: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

flyout.js – contains methods that control the speed and look of the flyouts used in WebSphere Portal. Use care when modifying these controls. Appendix D shows additional changes that can be made to this.

js_extensions.jspf – searches for and loads any theme extensions that are present. Any custom extensions that you have created that implement the JavascriptItems interface are pulled in.

2.4.1 Adding items to the onload In the course of your theme or portlet development you might want to add items to the onLoad() event of the page. The default themes make extensive use of this event. A better approach is to use an addEvent method and add items to the onLoad() event. For example: if (window.addEventListener) //DOM method for binding an event window.addEventListener("load", methodName(), false) else if (window.attachEvent) //IE exclusive method for binding an event window.attachEvent("onload", methodName())

2.5 Additional JSP files used by the portal theme The following are additional files used by the portal theme: flyout.jspf renders the flyouts for the dynamic menus used by the portal. Use care when modifying this file. Appendix A shows additional changes that can be made to this. mainMenu.jsp renders the launch menu and should not be modified. To add pages to the Main Menu, create pages at the first level underneath Content Root. All pages are picked up by default there. To prevent pages created at this level from being visible, set the hidden flag for the page parameter for the content-node tag in XML.

Note: You can still view and work with pages that are marked as hidden in Administration portlets. You can also create a direct URL to the hidden page so that the page can be accessed from other areas of the site, such as the page menu. You can use the following XML snippet: <content-node action="update" ...> .... <parameter name="com.ibm.portal.Hidden" type="string" update="set"><![CDATA[true]]></parameter> ... </content-node> Or you can use personalization rules to hide pages. For more details on this, refer to the WebSphere Portal Version 6 information center’s topic, Step 6: Hiding pages on the site .

pageContextMenu.jsp, portletContextMenu.jsp render the page and portlet context menus that you see as drop-down controls. They should not be modified.

Page 8: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

2.6 Tags used by WebSphere Portal JSPs When creating your own theme, the most commonly used JSP tags used are the <portal-navigation/> tags. These tags should not be used in portlets and are reserved for use only inside the themes and skins. 2.6.1 Navigational tags <portal-navigation:navigation> This tag is used to set up parameters for the navigation tags. Basically you pass in the start and stop level for the navigation loop. If you want it to start at navigation level 2 and stop at navigation level 3, it will render the first level of navigation under portal home, such that you will see all the pages, labels, and URLs from that level. <portal-navigation:navigationLoop> This tag always occurs inside the <portal-navigation:navigation> tag. It loops through the navigation levels specified in the navigation tag above and displays the markup contained in the loop for each node that is pulled out. This would be the markup that exists between the begin and end tags. The body of this tag should contain your markup for creating the links to the page and for calling the context menus for the page if it is within the selection path. Refer to the existing sidenav.jspf ile for more information on what the body of this tag should include. f

<portal-navigation:navigationShift by="number" maxPages="number"> This tag is available for shifting between visible pages, so that if you are currently showing the first five pages, you can scroll over as many pages that you’ve specified. If the tag is not used, then all pages are shown for that current level of navigation. An example of this tag’s usage is: <portal-navigation:navigationShift by="-5" maxPages="6">

<portal-logic:if pageAvailablePrevious="yes"> <td class="wpsUnSelectedPage"> <a href="<portal-skin:urlParent />"> - </a> </portal-logic:if> <portal-logic:if pageAvailablePrevious="no"> <td class="wpsUnSelectedPage"> </portal-logic:if> </portal-navigation:navigationShift> <portal-navigation:navigationShift by="+5" maxPages="6"> <portal-logic:if pageAvailableNext="yes"> <a href='<portal-skin:urlParent/>'> + </a> </td> </portal-logic:if> <portal-logic:if pageAvailableNext="no"> </td> </portal-logic:if> </portal-navigation:navigationShift> To use this example, you also need to add this tag lib to the default.jsp file: <%@ taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.0/portal-skin" prefix="portal-skin" %>

Page 9: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

<portal-navigation:navigationUrl type="link|expand|collapse|launch" varname="node_name" var="variable_name"/> This tag is always used within the navigation loop tags to render links to various navigation nodes. Link and Launch are very similar; the other two are used when that page has a child node and you want to expand the list to see the child nodes. To create the link, you add code such as <a href="<portal-navigation:navigationUrl type='link' />"><portal-fmt:title/></a> <portal-navigation:url> This tag lets you create links to the screens, commands, or home attributes from within your theme. <portal-navigation:urlGeneration> This tag lets you create links directly to various portal resources, either pages or portlets, and is very similar to the URLs you can create via the URL generation API. The WebSphere Portal information center and various technotes go into further detail in creating these links. <portal-navigation:urlParam name="parameter_name" value="parameter_value"> With this tag, you can add various parameters to the URL. If you have targeted a portlet, the parameters can then be retrieved by the getParameter method of the portlet request for a standard portlet. If the URL tag that is the holder for this parameter tag targets just a page, the parameters are available to all portlets written to the IBM Portlet API on the page, but they will not be available to JSR 168-Compliant portlets. 2.6.2 Format tags <portal-fmt:title varname="scripting_variable"/> When used inside a navigation loop tag, this tag pulls the page’s title based on the locale, while allowing you to pull the title for any item that supports the localized interface. <portal-fmt:description varname="scripting_variable" /> This tag pulls the description for the object that supports the localized interface. <portal-fmt:text key="key" bundle="bundle"> This tag returns the given text in the specified language. Java Standard Tag Library (JSTL) should be used instead of these tags, where applicable. <portal-fmt:textParam> This tag can be used only within the text tag. If the key in the bundle file has a place holder in the format of {0}, then this tag can be used to substitute a value for the place holders. For example, the file nls.engine contains

welcome = Welcome {0}! Then, in the JSP file, you can put this snippet: <portal-fmt:text key="welcome" bundle="nls.engine"> <portal-fmt:textParam>World</portal:textParam> </portal-fmt:text> The value for {0} will be replaced with World. <portal-fmt:user attribute="value"/> This tag returns any attribute as defined in IBM WebSphere Member Manager (WMM) for the current user.

Page 10: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

2.6.3 Logic tags <portal-logic:if attribute="value"> This tag checks a variety of conditions that might exist, including loggedIn, nodeInSelectionPath, portletMaximized, and portletState. You can use this tag to change various aspects of the theme to be conditional. <portal-logic:pageMetaData/> This tag accesses the metadata for the page. <portal-logic:unless> This tag is the opposite of the <portal-logic:if attribute="value"> tag above but works on the same conditional states as that tag; that is, if the condition is true, the ontent of the tag is not written to the HTML output and instead the content is rendered. c

<portal-logic:urlFindInSkin file="file_name"> and <portal-logic:urlFindInTheme file="file_name"> These tags let you build URLs that point to the files as they exist in either the theme or skin without having to hard-code the URL. You can have the URL for all your images use this tag and place the images in your theme directory, after which WebSphere Portal will find them and generate the correct URL. Using this tag lets the portal engine determine the correct URL path for the image and write that to the HTML output. An example is

<portal-logic:urlFindInTheme file="images/toolBar/help.gif"/> where the .gif file exists at the following location on the file system:

wps.ear\wps.war\themes\html\IBM\images\toolBar 2.6.4 Other items affecting theme rendering When using the default theme as the basis for your new custom theme or when developing your own theme, using the guidelines found in the information center, you must be mindful of the theme policy. The theme policy affects how parts of the WebSphere Portal-provided tags render. Theme policies can cause these tags to change and can leave you with a theme other than the default theme. For example, some of the theme policies instruct the theme not to render the theme extensions, so the theme extension tags do not render any output when called. Another item affecting rendering is the color palette. You can select various color palettes based on several factors to change what color scheme the theme uses. For example, you can use the same theme but a different palette to deploy across different business units. Finally, you can extend your theme by using the theme extensions framework. These items are examined in detail later in this document. Special Notes:

• When you want to modify the look and feel of palettes, be aware that these are separate portal pages, and they have their own assigned themes. If you want to modify properties such as the colors and images, you must make sure to edit the correct theme. The pages on which the palettes are use the IBM theme by default.

• To change the icon for the portlet, you must define the name of the .gif file in the

configuration parameters for the portlet. The parameter name is "portlet_Icon_name",

Page 11: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

and the value can be just the name of the file, "my_weather.gif". Check the "My Weather" portlet as a guide, if you still have it installed.

• The image file must be located in the <theme>/images/palette/portlets directory. After

making the change in the configuration of the portlet, you may need to log out and open a new browser before you see the new image.

3 Theme policy The theme policy is a new concept that was introduced with version 6.0 of WebSphere Portal. This policy controls how various parts of the theme are displayed on the page. Using various theme policies, you can have one theme but have several looks to your portal. The only way to update a given theme policy is through the XML configuration interface. You can apply this policy by using either the properties portlet or the XML configuration tool. As with many other aspects of themes, you need only set a theme policy on a page if it needs to be different than the parent policy. Once this setting is set on a page, it is handled through the process of inheritance, cascading down through any children pages, until it gets to a page with an explicit definition. The theme policy contains several attributes, each one controlling a single aspect of the page. For example, the Boolean renderBreadCrumb attribute controls whether the breadcrumb displays, and the breadCrumbMaxLevels attribute controls the number of steps listed in the breadcrumb trail when it displays. The theme policy can control whether any theme extensions are run and rendered into your theme. Be mindful of this control when setting the renderExtensions attribute to false, as it can cause all the theme extensions to fail. Table 1 lists all possible theme policy attributes and their type. Table 1. Theme policy attributesAttribute Type Function

renderMainMenu Boolean If true, the main menu is rendered.

renderTopNavigation Boolean If true, top navigation is rendered.

renderMainMenuActions Boolean If true, the main menu actions are rendered.

renderSelfCare Boolean If true, Selfcare is rendered.

renderBreadCrumbTrail Boolean If true, the breadcrumb trail is rendered.

render renderSearch Boolean If true, search is rendered.

renderToolBar Boolean If true, the toolbar is rendered.

renderContentPalette Boolean If true, the portlet palette is rendered.

renderPeoplePalette Boolean If true, the people palette is rendered.

renderContextMenus Boolean If true, context menus are render.

renderSideNavigation Boolean If true, side navigation is rendered.

renderTaskBar Boolean If true, the task bar is rendered.

Page 12: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Attribute Type Function

renderFavorites Boolean If true, favorites is rendered.

renderExtensions Boolean If true, extensions are rendered.

renderBannerTitleGraphic Boolean If true, the banner title graphic is rendered, as long as one exists.

renderPortletFragmentIDAnchor Boolean Determines if the user is on a palette page.

renderBannerTitle Boolean If true, the banner title is rendered, as long as one exists.

breadCrumbMaxLevels Integer Indicates the number of steps listed in the breadcrumb trail.

breadCrumbStartLevel Integer Indicates which level to start the breadcrumb trail.

rootNavigationStartLevel Integer Indicates the start level for root navigation.

rootNavigationStopLevel Integer Indicates the stop level for root navigation.

topNavigationNumRows Integer Indicates the number of rows to render for top navigation.

topNavigationStartLevel Integer Indicates the start level for top navigation.

topNavigationStopLevel Integer Indicates the stop level for top navigation.

sideNavigationStartLevel Integer Indicates the start level for side navigation. The default WebSphere Portal installation comes with ready-to-use policies, including SingleTopNav, SingleTopNavMinimal, DoubleTopNav, DoubleTopNavMinimal, SideNavOnly, SideNavOnlyMinimal, NoTheme, Federation, SingleTopNavLevel2, and Palette. The last three policies should not be modified because they are used on various parts of the default theme for flyouts and other pieces of the interactive theme. Additionally, the Federation policy cannot be applied to any page using the XML configuration tool or the properties portlet. Here are descriptions of the theme policies: SingleTopNav – used when you want only one level of top navigation. It renders only five levels in the breadcrumb trail and only three levels of side-level navigation. SingleTopNavMinimal – is similar to the one above and is used when you want a minimal amount of navigation options and links on the page. The self care, breadcrumb trail, search control, toolbar, palettes, context menus, favorites, extensions, title, and graphics in the title bar are not rendered. Top and side navigation and the main menu are rendered, but all the actions in the main menu are not rendered. DoubleTopNav – quite similar to the SingleTopNav except that two levels of navigation are rendered along with the top level. All other navigation is picked up by the side navigation. DoubleTopNavMinimal – quite similar to the SingleTopNavMinimal, but with the navigation, it changes as in DoubleTopNav. SideNavOnly – causes all levels of navigation to be rendered in the side navigation area.

Page 13: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

SideNavMinimal – similar to the other minimal policies, but all side navigation is rendered on the side navigation area. NoTheme – has all elements of the theme not to be rendered. This policy is similar to a plain theme template that could be used for a print preview, if you wanted just to print the content of the portlet. For more information on these policies and their specific attributes, refer to the information center’s Theme policies topic. When working with the theme policy in your JSP files, use the <portal-theme-ext:initthemepolicy/> tag to set up the theme policy. This tag is in the IBM theme in the default.jsp file and makes two variables available to the JSP files: portalThemePolicyMap and portalThemePolicyPath. The theme policy path is the theme policy name, like SideNavMinimal. This attribute is the same one you use when exporting the theme policies. This tag checks whether a theme policy has been set via the URL state and, if not, it checks on the page to determine whether a theme policy has been set. If it cannot find the theme policy, it uses the default value of SingleTopNav. Add the following code snippet to your default jsp file in your theme to load the map into a bean for easy access elsewhere in your JSP: <jsp:useBean id="themePolicy" class="com.ibm.portal.theme.policy.ThemePolicyBean" scope="page"/> <% themePolicy.setValuesMap(portalThemePolicyMap);%>

3.1 Exporting and updating a theme policy To update the theme policy, first export it using the XML configuration utility indirectly. The URL location specified points to an XML file that you want it to create. The xmlaccess files are indirectly used to access the theme policy utility. Use this example as your input file: <?xml version="1.0" encoding="UTF-8"?><request xsi:noNamespaceSchemaLocation="PortalConfig_1.4.xsd" create-oids="true" type="export" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <portal action="locate"> <policy-node action="export" label="WebPage" type="theme" path=""> <url>file:///c:/temp/exportThemePolicies.xml</url> </policy-node> </portal> </request> If you want to export only one policy, replace the path attribute with the name of the theme policy. For example, if you had a policy named TestThemePolicy, replace path="" with path="TestThemePolicy".

Page 14: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

After you have generated the export XML file, update any attributes (such as changing the renderExtensions attribute from true to false), and then use that as your import file into the XML configuration tool in the next step. This operation is necessary when we get to the next step of creating your own theme policy pieces. The XML file that is generated cannot be used as an import file to the XML configuration utility. You must always pass the utility an XML file that points to the actual policy XML file. This file will either be the file used to update the existing policy or to create the file when doing an export operation: <?xml version="1.0" encoding="UTF-8"?> <request xsi:noNamespaceSchemaLocation="PortalConfig_1.4.xsd" create-oids="true" type="update" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <portal action="locate"> <policy-node action="update" label="WebPage" type="" path=""> <url>file:///c:/ibm/PortalServer/bin/exportThemePolicies.xml</url> </policy-node> </portal> </request> If you wanted to delete your theme policy, the XML would look like this: <request xsi:noNamespaceSchemaLocation="PortalConfig_1.4.xsd" create-oids="true" type="update" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <portal action="locate"> <policy-node action="delete" label="WebPage" type="theme" path="TestThemePolicy"> </policy-node> </portal> </request> After you have created your new theme, assign it to a page by specifying the metadata attribute com.ibm.portal.ThemePolicy. This example sets the theme policy SingleTopNavMinimal to the page ThemePolicyPageTest: <request type="update" create-oids="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PortalConfig_1.4.xsd"> <portal action="locate"> <content-node action="update" ordinal="last" uniquename="ibm.portal.ThemePolicyPageTest" content-parentref="Content.Root" active="true" allportletsallowed="false" create-type="explicit" objectid="wp.theme.policytestpage" type="page"> <supported-markup markup="html" update="set"/> <!--@LocaleData_1@--> <parameter name="com.ibm.portal.ThemePolicy" type="string" update="set">theme/SingleTopNavMinimal</parameter>

Page 15: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

</content-node> </portal> </request> Here are some tips to follow when updating a theme policy:

If you are only updating a theme policy, you must perform these steps:

Export the theme policy. Edit the values of the attributes to be updated. Use the XML configuration interface to import your file, which is referenced from the

actual input file to xmlaccess. When updating, if you are also extending a theme policy by adding attributes to it, the attributes must also be added to the root theme policy:

Export the entire theme policy structure. Edit the root theme policy. Edit the theme policy to be updated by adding the attribute, if the value is different than

the root theme policy. Import the file that references the file that has the updated definitions.

If you are modifying only the value of an attribute that already exists in a theme policy, use the following guidelines:

Export the theme policy you want to modify. Make the appropriate changes to the attribute. Import the file that references the file which has the updated definitions.

3.2 Adding custom policy attributes When creating your own theme policy, you can also add your own custom attributes, which can be of type integer, Boolean, or string. These attributes can then be used in your JSP file to control the rendering of certain parts of your theme. To create your own custom theme policy attribute, export the root theme policy by simply exporting everything as described above. After you have the output, add the following to the root policy definition that exists at the top of the XML file that was created from the export operation: <policyValue Name="renderTestAttribute" Factory="com.ibm.wps.policy.parse.BooleanFactory"> <value>false</value> </policyValue> <policyValue Name="renderTestAttributeLock" Factory="com.ibm.wps.policy.parse.BooleanFactory"> <value>false</value>

Page 16: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

</policyValue> Then import the file back into WebSphere Portal using the configuration interface, which adds them to all theme policies. In one of your theme JSP files, put the following code snippet: <% boolean isTestAttribute = themePolicy.getValueAsBoolean("renderTestAttribute", false); if(isTestAttribute){%> <p> Display this paragrah if renderTestAttribute is true. </p> <%}%> Because this value is a Boolean type, we used the getValueAsBoolean method, but the theme policy object actually has three accessor methods: • getValueAsBoolean(String key, boolean defaultValue); • getValueAsInt(String key, int defaultValue); • getValueAsString(String key, String defaultValue);

where key is the name of the attribute as defined in the theme policy and defaultValue is the value that is used if the attribute value cannot be retrieved from the theme policy. Next, create your own policy called test policy. Included in the Downloads that accompany this white paper is a file to be used to import this theme policy (newtesttheme.xml). The theme policy contained in the newtesttheme.xml is a copy of the DoubleTopNav, but with the added item of the renderTestAttribute. This file has the renderTestAttribute set to true and once we apply it to a page, we will be able to see the HTML text rendered in the page that was contained in the if tag that we added above. After creating our own test policy and importing it, we assign the test policy to a page that has the theme that we modified to have the scriptlet above. <policyValue Name="renderTestAttribute" Factory="com.ibm.wps.policy.parse.BooleanFactory"> <value>true</value> </policyValue> In figure 2, we see that based on the theme policy, the paragraph is visible. Figure 2. Visible paragraph

Page 17: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

3.3 Accessing standard theme policy attributes Another way to access the theme policy attributes in a JSP file is to load the themepolicy for the page directly into the page for reference inside the expression language for the JSP. To do this, add the following snippet in the default.jsp file for the standard IBM Theme: <portal-theme-ext:initthemepolicy/> <jsp:useBean id="themePolicy" class="com.ibm.portal.theme.policy.ThemePolicyBean" scope="page"/> <% themePolicy.setValuesMap(portalThemePolicyMap);%> Then in your JSP code, retrieve the value: <c:if test="${themePolicy.renderTopNavigation}"> <p> Display this paragrah if renderTopNavigation is true and we are loading from the page map. </p> </c:if> The one limitation is that only the standard theme policy attributes are available in this way. You must use the standard getter methods to get any values that you add to extend the theme policy. If you want to extend this access so that you can call the bean as above for your own attributes, you can do the following: First, in Rational® Application Developer create a Java project, pointing to the WebSphere Portal 6.0 runtime and JDK. Next, add the following JAR file from /shared/app to the buildpath: wp.theme.themepolicy.jar file. Finally create a class like the following: package com.ibm.wps.l2.themepolicy; import com.ibm.portal.theme.policy.ThemePolicyBean; public class MyThemePolicyBean extends ThemePolicyBean { private static final String RENDER_TEST_ATTRIBUTE = "renderTestAttribute"; /** * Controls whether the theme should render the title in the banner. * @return Returns the renderBannerTitle. */ public boolean isRenderTestAttribute() { return this.getValueAsBoolean(MyThemePolicyBean.RENDER_TEST_ATTRIBUTE, true); } } Add as many getter methods to the class for all of your custom attributes. Export this file as a JAR file, place it in the shared/app directory, and then restart the server. A sample is included in the Downloads theme_policy_test.jar. Change the policy bean loading to the following:

Page 18: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

<jsp:useBean id="themePolicy" class="com.ibm.wps.l2.themepolicy.MyThemePolicyBean" scope="page"/> <% themePolicy.setValuesMap(portalThemePolicyMap);%>

Then, you can retrieve your values like this:

<c:if test="${themePolicy.renderTestAttribute}"> <p> Display this paragrah if renderTestAttribute is true and we are loading from the page map. </p> </c:if>

4 Color palette The color palette lets you keep colors and certain icons separated from your stylesheets. This separation lets you change the color used on the page without needing to change any theme code. For example, public pages could be one color, and authenticated pages could be another color. The palette is defined by a properties file that is loaded by the stylesheet JSP files and then used to dynamically pull the properties to configure settings within the stylesheet files. The default palette can be overridden on a per-page basis.

4.1 Creating the palette The IBM-provided palettes are stored in the following location: /profiles/profilename/installedApps/nodename/wps.ear/wps.war/themes/html/IBM/colors. In this directory is a file called default.properties and a directory called default, where the default color §palette is included. A color §palette is defined by an identifier, which is the name of the directory and the name of the properties file. To create a new color §palette, for example, called testthis, create a properties file labeled testthis.properties and a folder labeled testthis. This property file stores parameters as key value pairs. In the default theme, all keys are prefaced with a setX, where X is a number. This preface is used to group the properties into sets of like properties. These are just a convenience and are not needed when creating your own §palette, but all color definitions must contain the same keys. Figure 3 contains a sample of some of these properties.

Page 19: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Figure 3. Sample properties

In the above samples, set1Text1 defines the text color in the selectedPage style class, but set1Text2 and set1Text3 do not have corresponding elements in the CSS box model. These values are included to provide multiple text colors for emphasis. The values could be used, for example, to specify the text color for <h1> and <h3> elements, or for <strong> text. If you need more values, add them. If you don’t need them at all, they can be deleted. There is no requirement for the contents of the property file, only that the keys used here correspond to their use in the stylesheet JSP files, and that all properties files contain the same keys.

4.2 Assigning the palette to a page After you have defined all your colors, you can then assign the palette to a page. The theme determines what color palette is in use by the metadata in the head.jspf file of the theme: <portal-logic:pageMetaData varname="pageMetaData"> <!-- pageMetadatatag colorPalette: ${pageMetaData.colorPalette} --> <c:set var="colorPalette" scope="request"> <c:out value="${pageMetaData.colorPalette}" default="default"/> </c:set> </portal-logic:pageMetaData> It gets a value from the page metadata and, if none is found, it uses a default color palette. It is important that all your themes have a default color palette and not just custom ones so that, if the metadata is missing, the page still renders. By default, pages do not have a colorPalette metadata value. For example, to assign the testthis color palette as a default to the pages, do the following: 1. Click the Page properties of the page on which you want to use a specific color palette. 2. Expand “Advanced options.” 3. Click “I want to set parameter.”

Page 20: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

4. Enter color§Palette as New parameter. 5. Enter the name of the color-palette property file as the New value. For example, enter

testthis to assign testthis.properties. 4.2.1 Referencing a color palette in CSSThe Styles_rules.jspf file loads the [color§Palette].properties file and stores it in a map request attribute, colors, for use by the CSS style definitions. The most efficient way to reference the values is with Expression Language (EL) expressions. EL expressions let you reference a map's values by a simplified dot notation. For example, ${colors.set1Background} retrieves the set1Background color. If you are only creating a new color palette for the existing theme, you need not modify the styles_*.jspf files. This modification is required only if you have added or removed keys from the properties files. For example, suppose you have added a new key that has a font color and a key for font size. You have two properties files, blue and red, and you have added this to the default.properties file. Next, add a style to the stylesheet JSP files so that this new key is pulled. Then, assign that style to the parts of the markup that you want.

5 Theme extensions Extensions aid in the building of a modular product with loosely coupled components. Extension points define how the component is to be extended, and the extensions comprise the additional functionality. WebSphere Portal uses the Eclipse plug-in framework to define the theme extensions. Visit eclipse.org for complete details on the plug-in framework and API. Like the Eclipse framework, theme extensions provide extension points to create and extend plug-ins. This extension allows for a highly customizable theme with little or no coding changes. Theme extensions let you add content to the rendered page without updating JSP files. WebSphere Portal provides several extensions that are ready to use, as is. Some of the default extensions include functionality to add flyouts or context menu items. 5.1 Theme extension APIs The APIs for theme extensions consist of several interfaces and a set of classes that provide a default implementation to the core interfaces. We now briefly discuss the interfaces and then discuss the default implementations in more detail. Please see the imaged included in the zip labeled themeextension_class_diagram.jpg for more information. 5.1.2 Interfaces ThemeContent: All theme extensions indirectly extend the ThemeContent interface. Any element that contributes content to the theme using a defined extension point is of type ThemeContent. Two methods are defined in this interface:

Page 21: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

• getOrdinal - determines the priority, in which the lower the value, the higher the priority. If no value is specified using the plugin.xml file, then a value of -1 should be returned.

• init(ThemeContext context) - initializes the ThemeContext. Inherited methods:

• isActive method is inherited from com.ibm.portal.ActiveFlag. Returns true if the include should be rendered; otherwise, it returns false.

• SetInitializationData is inherited from

org.eclipse.core.runtime.IexecutableExtension. Sets the initialization data that is used to get attributes from the plugin.xml file. This method is passed an IconfigurationData object. This object represents the plugin.xml file of the extension and contains methods for extracting the attributes defined in the item element of the plugin.xml file.

The following three methods are inherited from com.ibm.portal.Localized:

• getDescription - returns the description. • getLocales - <lookup> • getTitle - returns the title.

There are two types of ThemeContent, ThemeItems and ThemeIncludes: ThemeItems Theme items are responsible for contributing content directly to the page. Two methods are defined in this interface:

• getTooltip(java.util.Locale) Returns the tooltip text for the current locale. If no value is specified or if there is an exception then null should be returned.

• newIconURL(com.ibm.portal.state.access.url.portalresource.State state) Returns the URL of type com.ibm.portal.state.DisposableURL for the specified icon. If the URL cannot be created or does not exist, a null value is returned. This method can throw a StateException.

There are two types of ThemeItem, ThemetextItem and ThemeLinkItem: ThemetextItem Contributes simple text. This interface adds one method:

• getText(java.util.Locale) Returns the text to be contributed to the markup.

ThemeLinkItem Creates a URL to contribute to the theme. This interface adds two methods:

• newURL Returns the generated URL of type com.ibm.portal.state.EngineURL or null if the user is not allowed to access the resource.

• RequiresPOST

Page 22: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

If the URL is the target of an action, this method should return true. ThemeIncludes ThemeIncludes are responsible for rendering their own content. RequestDispatcher should be used to include a JSP. The content is included using the render method. One method is defined in this interface:

• render() The render method is responsible for including the JSP.

ThemeJspInclude A ThemeJspInclude is responsible for rendering itself by invoking a JSP using a RequestDispatcher. The invoked JSP is responsible for maintaining the look and feel of the overall theme. One method is included in this interface:

• getJspPath() Returns the JSP path to be included.

ThemeContext Describes the current theme context. This interface formalizes the current context for a specific ThemeContent. An extension can declare a custom context in the plugin.xml file by including the context attribute in the markup describing the extension. Three methods are defined in this interface:

• getRequest() Returns the request associated with this context.

• getResponse() Returns the response associated with this context.

• initContext(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) Initializes the context.

Constants: There are three interfaces for defining constants to be used in theme extension. The constants represent the attribute names used in the default implementation of the theme extensions and match the attribute names as defined in the plugin.xml file. For example, the ThemeItemDescriptorConstants contains a constant named TOOLTIP_ATTRIBUTE. This constant maps to the tooltip attribute in the plugin.xml file: <item id="jsmith" class="com.ibm.wps.themeext.sample.ContactNames" firstName="John" lastName="Smith" email="[email protected]" tooltip="John Smith"/> ThemeContentDescritporConstants: Constants describing the XML attributes for a DefaultThemeContent. ThemeItemDescriptorConstants: Constants describing the XML attributes for a ThemeItem.

Page 23: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

ThemeJspIncludeDescriptorConstants: Constants describing the XML attributes for a DefaultThemeJspInclude. See the API for detailed information about all the interfaces discussed, which you can find in the developerWorks WebSphere document, Javadoc for WebSphere Portal V6.0 and V6.01. 5.1.3 Default implementations The theme extension APIs provide default implementations for the interfaces listed above. They provide a convenient extension point to the APIs without having to implement all the required methods. You can use these implementations rather than writing your own classes. In this section we discuss the attributes for each of the implementation classes. Most of the attributes are optional; however, those that are required are identified here. Some attributes do not fit to a particular type and are global: • id (optional) -- Specifies identification for this element. Although it is not required to make

this value unique, it is a best practice to do so. • class (required) -- Identifies which class should be used for this element. • tooltip (only used in theme items; optional) -- This text is rendered using the

ThemeExtensionItemToolTip tag. • context (optional) -- Identifies a custom ThemeContext to be used. If a context is not

specified, then a default one will be provided. DefaultThemeContent This class is the default implementation of ThemeContent and provides access to the following attributes defined in the plugin.xml file:

• description (optional) -- Provides a description about the extension. • ordinal (optional) -- This method determines the priority, in which the lower the value, the

higher the priority. The extension will be ordered based on their ordinal value, if specified.

• title (optional but should be included) -- Defines the title for the extension. All default implementations of ThemeItems (DefaultThemeLinkItem and DefaultThemeTextItem) extend this class, which means that they are inherently able to access these attributes when defined in the plugin.xml file. DefaultThemeItem This call provides a default implementation for ThemeItems and handles all the icon processing for the newIconURL method. This class works in conjunction with the ThemeExtensionItemIconUrl tag. Only the following attribute is defined for this default class.

iconName Defined the path and name of the icon to be used for this extension.

DefaultThemetextItem

Page 24: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Provides an implementation for a ThemetextItem. The text defined is rendered to the theme using the ThemeExtensionItemText tag. The following attribute is the only one added by this class:

text (required) Text to be contributed to the markup.

DefaultThemeLinkItem This implementation creates a portal link to the specified content node. For this implementation the following methods return false or null:

RequiresPOST (returns null) getTooltip (returns null) getOrdinal (returns 0) isActive (returns false) getLocales (returns false) isAllowed (always returns true)

The following additional attributes are added:

contentNode This attribute should be the uniqueName of the page you are targeting.

useNewWindow

Used when targeting new windows like flyouts. The value would be true. DefaultThemeJSPInclude This class provides the implementation to include a JSP in the theme. The render method is invoked to call the RequestDispather to include the desired JSP file. The following attributes are added with this class:

Jsp (required) The relative path to the JSP to be included.

The previous section discussed the default implementations and the attributes required in the plugin.xml file. If you decide not to use the default implementation and create your own, it is important to understand how these attributes are resolved. It would be a best practice to use the attribute names described above, but it is not required. There may also be cases in which you need to extend the default implementation to add more attributes. The following is a snippet of a plugin.xml file that uses a ThemeTextItem. For this example, we only use a few of the possible predefined attributes, while adding a custom attribute: <extension point="com.myco.theme.plugin.Sample" id="Sample_01" name="Test_01" > <item id="Page1" class="com.myco.sample.TextSample" description="This is sample text"

Page 25: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

text="some value for page 1" text2=”some other text”/> </extension> This extension uses a class named TextSample as defined in the class attribute. TextSample extends DefaultThemeTextItem and overrides the setInitializationData method to process that new attribute, text2. When the setInitializationData method is called on TextSample, the IConfigurationElement is used to retrieve the text2 attribute. The IconfigurationElement object contains a method to retrieve all attributes defined in the item element of the plugin.xml file. Example: public void setInitializationData(IConfigurationElement element, String arg1, Object arg2) throws CoreException { super.setInitializationData(element, arg1, arg2); String value = element.getAttribute(“text2”); if(value != null){ myCustomValue = value; } } The attribute is retrieved from the IconfigurationElement by use of the getAttribute method. This is how the plugin.xml attributes are realized in the theme extension code. 5.1.4 Default extension points The default themes provide a set of extension points. The Suggested Interface field describes the interface that provides the information required by the default extension point. Type enforcement is not performed at runtime. However, if an implementation does not provide at least the information required by the Suggested Interface, the extension might not display correctly in the theme. The following list describes the extension points provided: com.ibm.portal.theme.plugin.MetaTagDataItems • Description: Provides components the ability to add data to the meta tags of a page. • content type: ThemeItem • Interface: ThemeTextItem com.ibm.portal.theme.plugin.Styles • Description: Provides components the ability to contribute CSS to the page. • content type: ThemeItem • Interface: ThemeTextItem com.ibm.portal.theme.plugin.Javascript • Description: Provides components the ability to add JavaScript to the page. • content type: ThemeItem • Interface: ThemeTextItem com.ibm.portal.theme.plugin.HorizontalPageBarItems

Page 26: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

• Description: Provides components the ability to add JSP content to the horizontal page bar. • content type: ThemeInclude • Interface: ThemeJspInclude com.ibm.portal.theme.plugin.VerticalPageBarItems • Description: Provides components the ability to add JSP content to the vertical page bar. • content type: ThemeInclude • Interface: ThemeJspInclude com.ibm.portal.theme.plugin.MainContextMenuItems • Description: Provides components the ability to add an item to the main context menu. • content type: ThemeItem • Interface: ThemeLinkItem com.ibm.portal.theme.plugin.PageContextMenuItems • Description: Provides components the ability to add an item to the page context menu. • content type: ThemeItem • Interface: ThemeLinkItem com.ibm.portal.theme.plugin.PortletContextMenuItems • Description: Provides components the ability to add an item to the portlet context menu. • content type: ThemeItem • Interface: ThemeLinkItem com.ibm.portal.theme.plugin.Flyouts • Description: Provides components the ability to add flyouts to the page. • content type: ThemeInclude • Interface: ThemeJspInclude 5.1.5 Plugin.xml The plugin.xml file is used to define extensions and extension points. The following elements should be used within the plugin.xml file: plug-in This element is the root of the XML file and the following attributes should be defined:

• id This attribute is the root identification for the plug-in. This ID combined with the ID in the extension-point element are used to determine the entire extension point. For example, if the ID defined in the plug-in element is com.ibm.portal.theme.plugin and the ID attribute in the extension-point element is “Styles”, then they would combine to give the fully qualified extension point the name of com.ibm.portal.theme.plugin.Styles.

• name Name used to identify the plug-in.

• version The version number of the plug-in.

• provider-name This name should identify the vendor writing the plug-in.

extension-point

Page 27: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Used when defining a new extension point. This element is a child element of the plug-in element and has the following attribute:

• id Unique identifier of this extension point that’s used in conjunction with the id attribute in the plug-in element to determine the fully qualified extension-point.

extension This element is also a child element of the plug-in element and is used to extend an extension point. When participating in theme extensions, this element will be used the most. The following attribute are defined:

• point Fully qualified name of the extension point you want to extend.

• id Unique identifier for the extension.

• name Unique name for the extension.

item This element is a child of the extension element and is used to define the ThemeContent. The attributes for this element vary depending on the extension-point being targeted. As outlined above we have defined the attributes required for the default implementation and also outlined how to define custom attributes. The following is an example of a plugin.xml file using a custom extension point: <?xml version="1.0" encoding="UTF-8"?> <plugin id="com.myco.theme.plugin" name="Theme Extensions Plug-in Page Value Samples" version="1.0.1" provider-name="IBM"> <!-- Creates a new extention-point named com.myco.theme.plugin --> <extension-point id="Sample" /> <extension point="com.myco.theme.plugin.Sample" id="Sample_01" name="Test_01" > <item id="Page1" class="com.myco.sample.TextSample" description="This is sample text" text="some value for page 1" text2=”some other text”/> </extension> </plugin> 5.1.6 Theme extensions in a JSP WebSphere Portal defines a set of JSP tags to initialize and process theme extensions, listed below. These tags should be used only within themes and skins and are not supported for use in portlets. For a complete listing of attributes, see the information center. themeExtension Starts the processing of the theme extension. The id attribute is used to identify the fully qualified extension point. themeExtensionLoop

Page 28: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Iterates through all extensions defined in the plugin.xml file. This tag makes the ThemeItem object available with a variable named themeExtension. themeExtensionItemTooltip Prints the tooltip specified. If a tooltip is not identified, then nothing is rendered. themeExtensionItemText Prints the text associated with the extension. The class defined in the plugin.xml for the extension must be of type TextItem. themeExtensionItemUrl Prints the URL associated with a ThemeLinkItem. themeExtensionItemIconUrl Creates a URL for the extension icon. themeExtensionRenderInclude Renders the content associated with ThemeIncludes, which are responsible for rendering their own content. Extensions are instantiated each time they are used via the IConfigurationElement#createExecutableExtension method. This instantiation for each access can have a performance impact, so the placement of an extension should be carefully considered. Avoid placing the extension inside nested loops. Custom extension point We now create a simple custom theme extension for displaying user contact information. To do this, you’ll need to perform the following steps:

1. Create a plugin.xml file defining your extension point and extensions. 2. If needed, create classes and interfaces for your extension. 3. Bundle your classes and plugin.xml file into a JAR file. 4. Place this JAR file under the portal/shared/app directory. 5. Update the theme to read the plug-in and properly render the extension. 6. Restart the server to force your new classes to be loaded.

Let’s start with creating the plugin.xml file. First, define the XML document: <?xml version="1.0" encoding="UTF-8"?> Next, define the root of the XML file; for the plugin.xml, it will be plug-in. The id attribute used in this element is combined with the extension-point ID to form the full extension-point ID. Also, define the name, version, and provider-name: <plugin id="com.myco.theme.plugin" name="Theme Extensions Contact Samples" version="1.0" provider-name="IBM"> Next, define the extension-point and give it an id of “ContactNames”. <extension-point id="ContactNames" />

Page 29: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Next, define an extension for this extension-point: <extension point="com.myco.theme.plugin.ContactNames" id="ContactNames_01" name="names_01"> Use the combination of the ID of the plug-in and the ID of the extension-point. The id and name are used during logging. While uniqueness is not enforced, try to create names unique to your plug-in. Next, we define items that correspond to the ThemeItem objects used in the theme. For a single extension-point you can have multiple items defined. The item also needs to define the class to be used and an ID. This example lists contacts with a first name, last name, and email ID: <item id="rywilson" class="com.ibm.wps.themeext.sample.ContactNames" firstName="Ryan" lastName="Wilson" email="[email protected]" /> Add a few more contacts, and the complete file will look like this: <?xml version="1.0" encoding="UTF-8"?> <plugin id="com.myco.theme.plugin" name="Theme Extensions Contact Samples” version="1.0" provider-name="IBM"> <extension-point id="ContactNames" /> <extension point="com.myco.theme.plugin.ContactNames" id="ContactNames_01" name="names_01"> <item id="rywilson" class="com.ibm.wps.themeext.sample.ContactNames" firstName="Ryan" lastName="Wilson" email="[email protected]" /> <item id="jwbarnes" class="com.ibm.wps.themeext.sample.ContactNames" firstName="James" lastName="Barnes" email="[email protected]" /> </extension> </plugin> Because custom attributes were used, we must create a class that will read them. In this class, define some constants that define the attribute names and override the setInitializationData method to read these attributes from the IconfigurationElement object. For this example we will extend the DefaultThemeTextItem class and take advantage of the default implementations. First, create an interface named IcontactNamesItem. Add the following constants to identify the attribute names from the item element:

Page 30: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

public static final String FIRST_NAME = "firstName"; public static final String LAST_NAME = "lastName"; public static final String EMAIL_ID = "email"; Next, define a set of Strings used to store the values of these attributes: private String firstName; private String lastName; private String email; Our interface will define the following getters and our implementation will set and return the values: public String getEmail(); public String getFirstName(); public String getLastName(); Create a class that extends DefaultThemeTextItem and also implements IContactNamesItem. Next, override the setInitialization method to retrieve the data: public void setInitializationData(IConfigurationElement element, String arg1, Object arg2) throws CoreException { super.setInitializationData(element, arg1, arg2); ring value lement.getAttribute(FIRST_NAME); St = e if(value != null){ firstName = value; } value = null; value = element.getAttribute(LAST_NAME); if(value != null){ lastName = value; } value = null; value = element.getAttribute(EMAIL_ID); if(value != null){ email = value; } } This coding is needed to create the bean that represents the ThemeItem. We could have optionally added another method to generate the markup, to email this customer. While defining the getters in the interface works when using a small number of attributes, there is a better solution if there are many more attributes defined. You could use a Map to store all the data, and then have one method for retrieving the desired attribute. We could rework the example so that the interface looked like this: public interface IContactNamesItem { public static final String FIRST_NAME = "firstName"; public static final String LAST_NAME = "lastName"; public static final String EMAIL_ID = "email";

Page 31: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

public String getAttribute(String key); } Our implementation would then change to the following: public class ContactNames extends DefaultThemeTextItem implements IContactNamesItem{ private Map attributes = new HashMap(); public void setInitializationData(IConfigurationElement element, String arg1, Object arg2) throws CoreException { super.setInitializationData(element, arg1, arg2); String value = element.getAttribute(FIRST_NAME); if(value != null){ attributes.put(FIRST_NAME, value); } value = null; value = element.getAttribute(LAST_NAME); if(value != null){ attributes.put(LAST_NAME, value); } value = null; value = element.getAttribute(EMAIL_ID); if(value != null){ attributes.put(EMAIL_ID, value); } } public String getAttribute(String key){ if(key !=null){ return (String)attributes.get(key); } return null; } } This implementation provides a cleaner solution, especially when there are a large number of attributes. To display the list of contacts on the top of the page, add this code in the default.jsp. The taglib for the theme extensions is already defined for the IBM-provided themes. If you are using a custom theme, add the theme extensions taglib definition: <%@ taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.0/portal-theme-ext" prefix="portal-theme-ext"%> The policies can determine whether or not theme extensions are enabled, so place your theme extension code after the theme policy initialization tag: <portal-theme-ext:initthemepolicy /> <jsp:useBean id="themePolicy" class="com.ibm.portal.theme.policy.ThemePolicyBean" scope="page" />

Page 32: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

<%themePolicy.setValuesMap(portalThemePolicyMap);%> Using the themeExtension tag, specify the extension point to include. We have defined the extension-point to be com.myco.theme.plugin.ContactNames, so this is the value to use in the id attribute: <portal-theme-ext:themeExtension id="com.myco.theme.plugin.ContactNames" > Next, we iterate through all extensions that have this point defined. This is the advantage of using theme extensions: Other WebSphere Portal administrators can create their own plug-in that extends this extension point and provide additions to the contact list, developers could also create a custom class that implements IcontactNamesItem and defines some custom logic, and all this can be done without needing to change the theme. While looping through the extension we cast the implicit themeExtension object that is provided in the themeExtensionLoop tag: <portal-theme-ext:themeExtensionLoop> <% com.ibm.wps.themeext.sample.ContactNames contact = (com.ibm.wps.themeext.sample.IContactNamesItem)themeExtension; After we have this object, we can use it to create a mailto link to this contact. out.println("<a href='mailto:" + contact.getAttribute(contact.EMAIL_ID) + "'>" + contact.getAttribute(contact.FIRST_NAME) + " " + contact.getAttribute(contact.LAST_NAME) + "</a><br>"); %> </portal-theme-ext:themeExtensionLoop> </portal-theme-ext:themeExtension>

6 Flyouts and context menus Let’s now discuss flyouts and context menus.

6.1 Flyouts Flyouts are customizations that take advantage of the theme extensions so that you don’t need to modify any theme JSP files. You can drop these JAR files into your shared app directory, restart the server, and the extensions are added to the theme as it renders. In this example we create a link to the enable tracing page so that it renders as a flyout. We need to create a Java project in Rational Application Developer (or your tool of choice), then add the portal runtime to the build path, and finally add these three JAR files: portal_root\shared\app\wp.theme.extensions.api.jar portal_root\shared\app\wp.theme.extensions.impl.jar portal_root\shared\ext\eclipse-runtime.jar For our example, we created a class that extends the class ThemeLinkItem.

Page 33: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

The methods outlined below in that class are doing most of the work. The following method creates the URL using a URL- generation API, making use of a helper class to do all the URL creation (for more information, refer to the developerWorks article, “Leveraging WebSphere Portal V6 programming model: Part 2. Advanced URL generation in themes and portlets.”): public EngineURL newURL() throws StateException { EngineURL result = null; try { result = ServletURLGenerator.generateUrlForFlyout("ibm.portal.Enable Tracing", "wps.p.Enable Tracing", aContext.getRequest(), aContext.getResponse() ); } catch (Exception ex) { System.out.println("There was a problem generating a flyout url"); } return result; } The following method specifies which graphic to display into the theme for expanding and collapsing this new flyout. This example uses a graphic of a pencil writing. You can use any graphic you want, but limit the size of the graphic to 21 pixels square. We use the helper class to generate the URL for us, which makes use of the URL-generation API: public DisposableURL newIconURL( State state ) throws StateException { DisposableURL url = null; try { url = ServletURLGenerator.getDisposableURL(aContext.getRequest(), aContext.getResponse(), "images/toolBar/tracing.gif"); } catch (Exception ex) { System.out.println("Unable to create the url"); } return url; } This method returns the title to be shown when hovering over the icon. It will also be used if the graphic URL cannot be retrieved: public String getTitle( Locale arg0 ) { return "Enable Tracing"; } This method renders in a new window instead of the current one. In a flyout, this will let it actually fly out over the current window instead of trying to be in the window: public boolean isNewWindow() { return true; } Finally, in your Java project at the root level, you need a plugin.xml file:

Page 34: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

<?xml version="1.0" encoding="UTF-8"?> <plugin id="com.ibm.wps.l2.whitepaper.samples" name="Theme Extensions Plug-in Samples" version="1.0.1" provider-name="IBM"> <extension point="com.ibm.portal.theme.plugin.Flyouts" id="WPSToolBaryFlyouts" name="ToolBarFlyouts"> <item id="DebuggingFlyout" class="com.ibm.wps.l2.whitepaper.samples.TracingFlyout" title="My Portal Extension" /> </extension> </plugin> This tells WebSphere Portal from where to load your extension, and where to add it in the theme extension hierarchy. Because we have not defined any new extension points, we do not have the tag for the extension-point. Instead, there is the extension we are adding to the already existing extension points. To deploy this implementation, put the graphic into the theme in use that will go under app_server_root/profiles/profilename/installedApps/nodename/wps.ear/wps.war/themes/html/themename/images/toolBar/. Next, export this Java project from your development environment. Note: Make sure you have specified 1.4 as the compiler compliance level, as Rational Application Developer uses 5.0 by default for Java projects. Take the JAR file that was exported in the previous step, drop it into portal_server_root/shared/app, and then restart the WebSphere Portal server. Using our example, you should now see the image for tracing in the upper-right-hand corner of your theme (see figure 4). Figure 4. Tracing image

6.2 Context menus Several context menus are included by default. At this time, do not use the theme extension points to create your own context menu. Instead, use the extension points to add items to the context menus, either for the page, the portlet, or the whole portal. You can selectively enable these menu items at runtime, based on criteria. To create a context menu item, create a class that extends ThemeLinkItem.

Page 35: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

In this class, we have overridden the setInitializationData to pull in the properties from our plugin.xml file, to parameterize this class (this is discussed in more detail in Section 5 Theme extensions, above): public void setInitializationData( IConfigurationElement arg0, String arg1, Object arg2 ) throws CoreException { String titleValue = null; titleValue = arg0.getAttribute( TITLE_ATTRIBUTE ); if ( titleValue != null ) { this.title = titleValue; } String descriptionValue = null; descriptionValue = arg0.getAttribute( DESCR_ATTRIBUTE ); if ( descriptionValue != null ) { this.description = descriptionValue; } String urlValue = null; urlValue = arg0.getAttribute( EXTERNAL_URL_ATTRIBUTE ); if ( urlValue != null) { this.externalUrl = urlValue; } } Based on the values that we pulled in, we create a URL to an external site: public EngineURL newURL() throws StateException { return new ExternalURL( this.externalUrl ); } Finally, we tell it to open the page in the existing window: public boolean isNewWindow() { return false; } Then, in the plugin.xml file, add the following: <extension point="com.ibm.portal.theme.plugin.PortletContextMenuItems" id="WPSExternalPortletMenuLinks" name="ExternalPortletMenuLinks"> <item id="GoogleLink3" class="com.ibm.wps.l2.whitepaper.samples.ExternalLinkItem" title="Google" description="Search for relevant items." url="http://www.google.com" /> </extension> This code loads these parameters into the class, using the setInitializationParameterData method. In this way, you can reuse the code above to create several links to add to the context menu of your choice (page, portal, or portlet).

Page 36: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Just by changing it to this example, it is added to the Main menu instead of the Portlet Context menu: <extension point="com.ibm.portal.theme.plugin.MainContextMenuItems" id="WPSExternalMainMenuLinks" name="ExternalMainMenuLinks"> <item id="GoogleLink1" class=" com.ibm.wps.l2.whitepaper.samples.ExternalLinkItem” title="Google" description="Search for relevant items." url="http://www.google.com" /> </extension> It would display in the drop-down control from the launch button instead of anywhere else in WebSphere Portal. Also included in the source code is an example of a Page Context menu item that points to a portal page. The class is InternalLinkItem and extends the ThemeLinkItem. This link points to a custom Create Page that could exist anywhere inside your portal, but will be accessible from the Page Context menus of any page, as long as the theme policy to render theme extensions is set to true. The method to create the URL also used the helper class and looks like the following (this helper class could let you target a portlet and pass parameters to it): public EngineURL newURL() throws StateException { EngineURL result = null; try { result = ServletURLGenerator.generateUrlStringServlet(page, null, null, context.getRequest(), context.getResponse()); } catch (Exception ex) { System.out.println("This exception in this code = " + ex); } return result; } In the plugin.xml file, we have the following to describe this new item: <extension point="com.ibm.portal.theme.plugin.PageContextMenuItems" id="WPSExternalPageMenuLinks" name="ExternalPageMenuLinks"> <item id="LinkToSearchResults" class="com.ibm.wps.l2.whitepaper.samples.InternalLinkItem" title="Create Page" description="Create a New Page." page="Create_Page" /> </extension> For full source code listing, see the attached code in the Downloads file (in the jar theme_ext_sample.jar in the following directory filesforwhitepaper\contextmenus). Several methods that are needed are defined in the source, but we have not modified them in any significant way.

Page 37: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

More information on these methods is also in the Javadoc for theme extensions, which can be found in the IBM WebSphere Portal Support technote #1247155, Theme APIs were not included in version 6.0 of IBM WebSphere Portal.

7 Development tools As the new version contains a significant level of complexity and improvement from previous versions, debugging all the interactions can be quite tricky. Luckily there are tools that make both HTML and JavaScript debugging easier. The tools we’ve used the most are plug-ins for Firefox that let you make real-time changes to the source code and see how it changes the look, without requiring you to refresh the browser. Also, you’ll be able to pinpoint which area needs changing easier. The first of these add-on tools is the Web developer plug-in for Firefox. The second is called Firebug, which is helpful for debugging issues with JavaScript and CSS. With both these plug-ins installed, you can inspect the rendered Web site in the following manner. Right-click an element and then choose Inspect Element (see figure 5). Figure 5. Inspect Element menu option

That action displays a window at the bottom of the browser that lets you see the HTML source code for the current element (see figure 6).

Page 38: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Figure 6. HTML source code displayed

Additionally, you can view the stylesheets, the JavaScripts, the DOM, and Net, which shows you the response time for various pieces to load. Next, on the right side, are the stylesheet definitions in use for this element (see figure 7). Figure 7. Stylesheet definitions

You can click to edit one of these or add a new setting to see how it would look in the rendered output. This change affects only this page view and is not persisted. With the Web developer toolbar you can also validate the HTML and CSS. You can outline all table elements, which can be helpful when the page is failing to load correctly. Line guides are also available to help with positioning of items when pixels measurements are used. A ruler is available that you can stretch directly on the page to measure distances between visual objects.

Page 39: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

There is a wealth of other options, and you’ll be sure to find both these tools very useful when developing themes and skins.

8 Migrating to version 6.0 from version 5.1 When migrating to version 6.0, you won’t want to convert all your skins and themes to full 6.0 style.

8.1 Adding drag and drop Using the steps below, you won’t need to rebuild your version 5.1 skins to support the drag-and-drop functionality of version 6.0. Refer to the Drag and drop JSP tags section in the information center to read about the tags you need in your skin JSP files to support this functionality. The main tags are: <dnd:DNDPortletHelper/> must be in the JSP; otherwise, it will not work. This tag loads several JavaScripts that are needed to make drag-and-drop work. <dnd:drag/> designates which part of the actual content is dragable. <dnd:drop/> sets up a drop zone. <dnd:dragHandle/> designates a part of the portlet to be used as the handle for drag and drop. First, in the control.jsp file, add the following import: <%@ page import="com.ibm.portal.content.LayoutNode"%> and tag lib declaration: <%@ taglib uri="/WEB-INF/tld/dnd.tld" prefix="dnd" %> After the wps:constant tag, add the following: <%! private static com.ibm.portal.identification.Identification identification; public void jspInit(){ try{ /* only perform this JNDI lookup once as this is an expensive call performance wise */ javax.naming.Context ctx=new javax.naming.InitialContext(); identification=(com.ibm.portal.identification.Identification) ctx.lookup("portal:service/Identification"); } catch (javax.naming.NamingException ne){ } } %> <% String currentLayoutNodeStr="";

Page 40: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

if (pageContext.getAttribute("currentLayoutNode", pageContext.REQUEST_SCOPE) != null) { LayoutNode currLayoutNode=(LayoutNode)pageContext.getAttribute("currentLayoutNode", pageContext.REQUEST_SCOPE); currentLayoutNodeStr=identification.serialize(currLayoutNode.getObjectID()); } else { LayoutNode currLayoutNode=(LayoutNode)pageContext.getRequest().getAttribute("com.ibm.wps.composition.element"); currentLayoutNodeStr=identification.serialize(currLayoutNode.getObjectID()); } %> <dnd:DNDPortletHelper /> These set up certain items in the context of the page so they are available for the later tags for the drag-and-drop feature. Next, directly after the above, add: <dnd:drag namespace="wp" type="portlet_windowID" value="<%=currentLayoutNodeStr%>" includeDragHandle="false" validator="com.ibm.wps.dnd.impl.DNDDragPortletValidator"> Then add this closing drag tag after the end of the portlet content in the control.jsp file: </dnd:drag> The next two tags you need to add are: <dnd:dragHandle> </dnd:dragHandle> The easiest place to add them is around the display part for the portlet title. 8.1.1 Drop zones You need to add a drop tag inside some element, either a div or table, so that it’s actually large enough to interact with. Start with UnlayeredContainer-H.jsp and first add: <%@ taglib uri="/WEB-INF/tld/dnd.tld" prefix="dnd" %> <dnd:DNDPortletHelper/> This area will be the start area: <dnd:drop namespace="wp" type="portlet_windowID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_INSTANCE_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" optionalActionJavascript="DND_MOVE_PORTLET_JS"> Then at the end of the section, add:

Page 41: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

<dnd:additionalAction namespace="wp" type="portlet_ID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" supportsMultiselect="true" multiselectDelimiter="__DND_DELIM__" optionalActionJavascript="DND_ADD_PORTLET_JS"/></dnd:drop> The easiest way to do this would be to add the following above your layout node: <dnd:drop namespace="wp" type="portlet_windowID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_INSTANCE_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" optionalActionJavascript="DND_MOVE_PORTLET_JS"><table><%-- We use these rows to make the vertical drop zones large enough to interact with. There is a problem when trying to get a table to expand to fill an entire region vertically. --%><tr valign="top"><td>&nbsp;</tr><tr style="height:100%;"><td>&nbsp;</td></tr><tr valign="bottom"><td>&nbsp;</td></tr></table><dnd:additionalAction namespace="wp" type="portlet_ID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" supportsMultiselect="true" multiselectDelimiter="__DND_DELIM__" optionalActionJavascript="DND_ADD_PORTLET_JS"/></dnd:drop> Then add your layout node loop. And then, at the end, add the following: <td style="width:10px;" valign="top"><dnd:drop namespace="wp" type="portlet_windowID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_INSTANCE_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" optionalActionJavascript="DND_MOVE_PORTLET_JS"><table><%-- We use these rows to make the vertical drop zones large enough to interact with. There is a problem when trying to get a table to expand to fill an entire region vertically. --%><tr valign="top"><td>&nbsp;</tr><tr style="height:100%;"><td>&nbsp;</td></tr><tr valign="bottom"><td>&nbsp;</td></tr></table><dnd:additionalAction namespace="wp" type="portlet_ID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" supportsMultiselect="true" multiselectDelimiter="__DND_DELIM__" optionalActionJavascript="DND_ADD_PORTLET_JS"/></dnd:drop> This code lets you drag before or after the portlet in that row. Next, modify the Unlayered-Container-V.jsp file to be able to drag and drop in the columns by adding this tag lib: <%@ taglib uri="/WEB-INF/tld/dnd.tld" prefix="dnd" %> and this tag: <dnd:DNDPortletHelper/>

Page 42: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

In your layout loop, add this code into a row or div element above where your portlet is called to render: <dnd:drop namespace="wp" type="portlet_windowID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_INSTANCE_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" optionalActionJavascript="DND_MOVE_PORTLET_JS">&nbsp; <dnd:additionalAction namespace="wp" type="portlet_ID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" supportsMultiselect="true" multiselectDelimiter="__DND_DELIM__" optionalActionJavascript="DND_ADD_PORTLET_JS" /> </dnd:drop> After the layout loop you should add a row or div like the following: <dnd:drop namespace="wp" type="portlet_windowID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_INSTANCE_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" optionalActionJavascript="DND_MOVE_PORTLET_JS">&nbsp; <dnd:additionalAction namespace="wp" type="portlet_ID" action="#" name="<%=com.ibm.wps.dnd.util.Constants.PORTLET_ID%>" validator="com.ibm.wps.dnd.impl.DNDPortletActionValidator" supportsMultiselect="true" multiselectDelimiter="__DND_DELIM__" optionalActionJavascript="DND_ADD_PORTLET_JS" /> </dnd:drop> These lines will give you the drop zones before and after the portlets in the column. 8.1.2 Theme changes Finally, you must add the stylesheet for the page. These styles give your drop zones visible areas during the drag and drop, so that it is easy to see what areas can be dropped into (very helpful when you have removed all portlets from a column): /* DRAG AND DROP */ .dndDropAware{ border: 0px; background-color: #FFEBC5; } .dndDropActive{ border: 0px; background-color: #FF9000; } .dndDragging{ width: 100%; filter: alpha(opacity=40); } .dndDragSelected{ border: 1px; background-color: #DDDDDD; } .dndMoveCursor{ cursor:move; }

Page 43: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

.dndDropCursor{ cursor: pointer; } .dndNoDropCursor{ cursor: not-allowed; } .layoutRow {width: 100%; } .layoutColumn {width: 100%; } The easiest way to do the drop zones is to copy the Unlayered-Container-v and h.jsp files to your skin from that of the IBM skin, as this sets up the drag-and-drop areas easily.

8.2 Considerations when migrating Default navigational state. This setting tells the portal container whether to render navigation nodes in an expanded or collapsed mode. This setting affects the rendering of the navigation tree as it appears on the left side by default. In WebSphere Portal version 5, this setting was set to true so that all nodes were shown as expanded on the right side. The setting caused the navigational loop tags to loop through all the child tags and display links to all the child pages. In version 6, this default state is set to false. If you use any coding to create drop-downs or flyouts that rely on the navigation loop tags producing links to all the children, you must set this value back to false. Otherwise, it will generate links to only the top level, and your drop-down lists will not appear fully populated. To override this setting in version 6, change the setting navigation.expansion.defaultstate to true in the Configuration Service. For more information on setting properties in version 6, see the information center topic, Setting configuration properties. Behavior of skins. When running your version 5.1 skins on 6.0, you will have an issue if your portlet supports the edit mode. In version 6.0 the concept of edit_defaults and personalize modes were added. The standard edit mode is not referred to as personalize, and those values are stored to the customization database domain. However, edit_defaults will save the preferences to the release domain. When any 5.1 theme is used on 6.0 and you click edit, it will go to the personalize mode, even when an administrator or manager is doing the editing. For this feature to work correctly, you must add the edit_defaults compatibility mode to your portlet and add a link in your skin. This provides you with a link from personalize that points to the edit mode, and then one that reads Edit Default Settings pointing to the edit_defaults mode. The following is an example from the 6.0 menu: <portal-navigation:urlGeneration contentNode="<%=pageID%>" layoutNode="<%=windowID%>" portletMode="edit" themeTemplate="" ><c:set var="title"><a href=<%= wpsURL.write(escapeXmlWriter); %>'<portal-fmt:text bundle="nls.titlebar" key="edit" /></a>

Page 44: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

<portal-navigation:urlGeneration contentNode="<%=pageID%>" layoutNode="<%=windowID%>" portletMode="edit_defaults" themeTemplate="" ><c:set var="title"><a href=”<% wpsURL.write(escapeXmlWriter); %>”><portal-fmt:text bundle="nls.titlebar" key="edit.defaults" /></a>

9 Conclusion This white paper has presented you with various points for customization and skills necessary to create a theme to meet your implementations needs. Additionally we have provided many tools with which you can create the look and feel that you need, while taking advantage of code reuse and the latest extension points of the 6.0 theme. An important point to understand is that when WebSphere Portal finishes with its aggregation (skins, themes, and portlets ) all that is returned is HTML, CSS, and Javascript. Keep this in mind when troubleshooting your themes and skins, to keep separate what is a possible WebSphere Portal code defect and what is an HTML display issue or limitation.

Page 45: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Appendix A: Drop-down navigation example Drop-down navigation is a common request for changing the navigational structure of WebSphere Portal. You could replace the table that is shown with whatever you wanted from the example in figure 8. Figure 8. Example drop-down navigation

If you want to create a drop-down menu in the version 6 theme, use the URL generation services and the navigation model API. In the JSP or servlet, find the following: NavigationModelHome home = (NavigationModelHome) ctx.lookup("portal:service/model/NavigationModel"); PortalStateManagerServiceHome serviceHome = (PortalStateManagerServiceHome) ctx.lookup("portal:service/state/PortalStateManager"); PortalStateManagerService service = serviceHome.getPortalStateManagerService(request, response); Then, add the following: // do something (create URLs etc.) urlFactory = service.getURLFactory(); EngineURL eUrl = urlFactory.newURL(Constants.SMART_COPY); //EngineURL eUrl = urlFactory.newURL(new StateHolder(), false, false, Constants.SMART_COPY); final SelectionAccessorFactory selectionFct = (SelectionAccessorFactory) service.getAccessorFactory(SelectionAccessorFactory.class); // get a selection controller that operates on the URL-specific state final SelectionAccessorController selectionCtrl = selectionFct.getSelectionAccessorController(eUrl.getState()); Finally, loop through the navigation model: NavigationModelProvider provider = (NavigationModelProvider) home.getNavigationModelProvider(); NavigationModel model = provider.getNavigationModel(request, response); NavigationNode nodeA = (NavigationNode)model.getRoot(); NavigationNode childNode = null; NavigationNode childNode2ndLevel = null; if(model.hasChildren(nodeA)) { Iterator iter = model.getChildren(nodeA); NavigationNode homeNode = (NavigationNode)iter.next(); Iterator homeIter = model.getChildren(homeNode); while (homeIter.hasNext()) {

Page 46: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

childNode = (NavigationNode)homeIter.next(); selectionCtrl.setSelection(childNode.getObjectID()); The root node is always ContentRoot, and in most all cases, Home is the first node under the Content Root. Iterate through those children to build the URLs, which will be built from this piece of code: href="<%=eUrl%> and the title from childNode.getTitle(localCurrent). In your default.jsp file, remove the sidenav.jsp include because you will no longer need side navigation. The files to update in your theme include flyoutTop.js, topNav.jsp, spacer.gif, and style.css. You can find these in the Download .zip file accompanying this document, under the following directory:

filesforwhitepaper\themes\testDropDown.

Page 47: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Appendix B: Right-hand navigation example Figure 9 shows an example of right-hand navigation. Figure 9. Right-hand navigation example

To achieve this, change this line in the default.jsp file from this: <table style="width:100%; height:100%;" cellpadding="0px" cellspacing="0px"> <tr><td valign="top"><portal-logic:if portletSolo="no"><%@ include file="./sideNav.jspf" %></portal-logic:if></td><td width="100%" height="100%" valign="top"><a name="wpsMainContent"></a><%-- Call the portal engine command to render the portlets for this page --%><div id="mainContent"><portal-core:screenRender/></div></td></tr></table> To this: <table style="width:100%; height:100%;" cellpadding="0px" cellspacing="0px">

<tr><td width="100%" height="100%" valign="top"><a name="wpsMainContent"></a><%-- Call the portal engine command to render the portlets for this page --%><div id="mainContent"><portal-core:screenRender/></div></td><td valign="top"><portal-logic:if portletSolo="no"><%@ include file="./sideNav.jspf" %></portal-logic:if></td></tr></table>

Page 48: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Appendix C: Removing unwanted space Other customizations you might want to make on your portal include reducing space between portlets. The portlet has several things that control the spacing, among which is the style:

#mainContent { padding:5px; }

Change it to zero and most of that space goes away; the last bit comes from

.wpsPortletBody { background-image:none; margin:5px; }

The wpsPortlet CSS has a 0px padding, and the rest should go away:

.wpsPortlet{ margin:5px; border-left: 1px solid; border-right: 1px solid; border-bottom: 1px solid; border-color: #CACACA; background-image:none; }

Additionally, the drag-and-drop controls take up some space. If you reduce the padding above, however, you can make it hard to interact with these controls. These controls are the drop zones for where you can drop the item you are dragging. If you want to disable drag-and-drop functionality, you can remove these tags from the portlet skin that is the default for the theme.

Page 49: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Appendix D: Changing properties of the flyout IBM provides two flyouts with the base theme, the people palette and the portlet palette. In your implementation, you might have your own directory search portlet that you want to place on the flyout page instead of using the default user People Search portlet. If you remove the existing portlet from the people palette and place your own directory search portlet on the page, you will encounter some problems (such as the URL not being created and exceptions listed in the log). When you removed the old portlet from the page, you removed a portlet instance with the unique name of ibm.portal.People Palette Control. The theme code that creates the URL to the flyout uses the URL generation services and targets the original People Search portlet by name. After you remove it, the URL generation services cannot find that portlet instance on the people palette page, so it is unable to render the icon. You have two options to address this issue: (1) The recommended way is to give one of the portlets on that page the above unique name, following only steps 2, 3, and 4 from the IBM Support technote “URLGeneration in WebSphere Portal v5.1 - Linking to another portlet”. Export the page (people palette) with this XML code: <?xml version="1.0" encoding="UTF-8"?> <request type="export" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PortalConfig_1.2.xsd"> <portal action="locate"> <content-node action="export" uniquename="ibm.portal.People Palette" /> </portal> </request> The result is similar to this output: <component action="update" active="true" deletable="false" domain="rel" modifiable="false" objectid="7_UV9FQLI11O1BF026LUV0FD08G3" ordinal="-1" orientation="H" type="container" width="undefined"> <component action="update" active="true" deletable="false" domain="rel" modifiable="false" objectid="7_UV9FQLI11O1BF026LUV0FD08G7" ordinal="100" orientation="V" type="container" width="undefined"> <component action="update" active="true" deletable="false" domain="rel" modifiable="undefined" objectid="7_UV9FQLI11O1BF026LUV0FD0880" ordinal="100" type="control" uniquename="ibm.portal.People Palette Control" width="undefined"> <portletinstance action="update" domain="rel" objectid="5_UV9FQLI11O1BF026LUV0FD0884" portletref="3_UV9FQLI11O1BF026LUV0FD00C6"/> </component> </component> </component> Notice the line: uniquename=”ibm.portal.People Palette Control”.

Page 50: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Finally, reading from your output, you must modify one of the components surrounding the portlet and put the uniquename attribute on it with the exact value of ibm.portal.People Palette Control. (2) Another possible way to address the issue, though it was not tested, is to edit the URL generation tag in the head.jspf file and remove the layoutNode attribute from this line: url:"<portal-navigation:urlGeneration contentNode='ibm.portal.People Palette' layoutNode='ibm.portal.People Palette Control' newWindow='true' portletWindowState='Normal'><% wpsURL.write(out); %></portal-navigation:urlGeneration>", If you put more than one portlet on the page, you will also need to change the size of the flyout. To change the width, change the following lines in the file styles_theme.jspf: <%--=================================================== FLYOUT ===================================================--%> .portalFlyout{ position: absolute; left: -390px; width: 382px; background-color: ${colors.bodyBackground}; } Next, make sure that styles.jsp gets recompiled. If you do not have reloading enabled, you need to restart the server after editing the file. In our example, we changed it to the following: <%--=================================================== FLYOUT ===================================================--%> .portalFlyout{ position: absolute; left: -600px; width: 600px; background-color: ${colors.bodyBackground}; } When making these changes, also change the size of the scrollable area for the flyout: <div id="wpsFLYflyout" class="portalFlyout" > <iframe class="portalFlyoutIframe" id="wpsFLY_flyoutIFrame" frameborder="0px" width="380px" name="wpsFLY_flyoutIFrame" src="<portal-logic:urlFindInTheme file="./flyoutInit.html" />" scrolling="auto"></iframe> </div> In the flyout.jspf file, the value of 380px needs to be changed to whatever you had set the flyout site to above. In our example we set it to 600. Then if you want to change the speed at which the flyout happens, change two parts of the JavaScript. First, in the js directory, open the flyout.js file and change these lines:

Page 51: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

wpsFLY_minFlyout=0;var wpsFLY_move=25;if (wpsFLY_isIE) wpsFLY_move=20;var wpsFLY_scrollSpeed=1;var wpsFLY_timeoutID=1;var wpsFLY_fromTop=100;var wpsFLY_leftResize;var wpsFLY_browserDimensions=new The move variable must be changed, if you want to change the speed of the flyout. In the same file farther down, change these two lines: setTimeout('wpsFLY_internalScroll()',1);};function wpsFLY_internalScrollLeft() { The default is 20. In the example, it is 1. Then on this line, change these lines: setTimeout('wpsFLY_internalScrollLeft()',1);};function wpsFLY_internalResizeLeft(){ After you make these changes, the flyout will move at a faster speed. These methods wait X number of milliseconds (from the timeout above) to move it to what you specified above (in the wpsFly_move settings).

Page 52: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Resources • IBM WebSphere Portal Version 6.0 Information Center:

http://publib.boulder.ibm.com/infocenter/wpdoc/v6r0/index.jsp?topic=/com.ibm.wp.ent.doc/wps/adsetcfg.html

• IBM developerWorks WebSphere Portal zone:

http://www.ibm.com/developerworks/websphere/zones/portal/

About the authors Ryan Wilson is the Technical Lead for the WebSphere Portal Level 2 API/Migration team in RTP, North Carolina. His areas of expertise include J2EE application development with IBM WebSphere Studio and Rational Application Developer. He has participated in many projects, including internal tools development. Other works include the IBM Rational Application Developer V6 Portlet Application Development and Portal Tools Redbooks publication. Ryan holds certifications in WebSphere Portal development(5.1, 6.0), and is a Java Certified Programmer, and Java Certified Web Component Developer.

James Barnes is currently the Level 2 Team Lead for the WebSphere Portal API/migration team. Jim joined IBM in 1999 first working the Lucent outsourcing account. After joining Level 2 in 2003, he started focusing on development-related issues. Jim holds a BS from Virginia Tech in Agriculture and Applied Economics. Other works include the 5.1 WebSphere Portal Handbook and extensive articles on the Support web site on migration and development. He holds Certifications for WebSphere Portal development(5.1, 6.0) and WebSphere Portal Administrator(5.0, 5.1, 6.0).

Acknowledgements The authors extend special thanks to William Trotman and Morgan Kinne for their valuable help in preparing this document.

Page 53: Developing Themes and Skins in IBM® WebSphere® Portal 6.0.X

Trademarks • IBM, Rational, and WebSphere are trademarks or registered trademarks of IBM Corporation in the

United States, other countries, or both. • Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun

Microsystems, Inc. in the United States, other countries, or both. • Other company, product, and service names may be trademarks or service marks of others. IBM copyright and trademark information: http://www.ibm.com/legal/copytrade.phtml This edition applies to version 6, release 0, modification 0 of WebSphere_Portal (product number 6.0.0.0) and to all subsequent releases and modifications until otherwise indicated in new editions.