门户用户界面框架组件
用户界面框架有很多组件。BEA开箱即用地实现了的所有用户界面组件。这些缺省的组件对某些应用 程序来说已经足够了,但我们还是很可能需要某个级别的定制。在深入讨论框架和定制之前,先让我们简略地看一下每个用户界面组件以及它们之间的关系。
观感(look and feel) 观感文件控制着门户应用 程序的样式和结构。这些文件都是引用特定皮肤(即look)和骨架(即feel)的简单XML文件。一个门户的观感是应用在桌面级别上的。虽然门户 开发人员会先选择一个门户的观感,但最终还是由门户 管理员来做最后的决定。
皮肤(skin) 门户皮肤就是门户的外观。这个外观由图像、级联样式表(CSS)和 JavaScript函数组成。这些文件一起描述了门户的样式和行为。皮肤还为移动设备包含特定于设备的样式。
Portal皮肤由位于skin目录下的skin.properties文件来配置。这个配置文件可用来定义图像、CSS以及 JavaScript文件和路径。另外,skin.properties文件还能用于定义与该皮肤一起使用的骨架(skeleton)名称和路径、添加方法到主体onload 和onunload 事件,以及定义附加信息。
当定制任何默认的 安装皮肤时,建议不要把额外的配置更改放在skin.properties文件中,而是放在一个可选的skin_custom.properties文件里。这样做的原因是门户升级的 安装 程序会覆盖掉skin.properties和skin文件所做的修改,也就覆盖掉了您所做的配置更改。
骨架(Skeleton) 门户的感觉取决于它的骨架。门户的结构由背后的XML决定,即到底是.portal XML文件格式还是 数据库本身。这个XML文件可以像可从桌面添加和删除的组件一样被修改。每个门户组件都与负责显示它的 JavaServer Pages ( JSP)页面相关。这些 JSP页面的集合就构成了门户骨架。骨架也可包含特定于设备的 JSP,这些 JSP指明用于查看移动设备上的Web应用 程序的结构。
门户骨架还能使用skeleton目录下skeleton.properties文件中的额外配置信息。通常情况下,该文件在创建定制骨架时使用。您可以设置 JSP的搜索路径,这样就能在试图查找 JSP时使用其他一个或一系列路径。例如,假如您想修改book. jsp,只需简单地给修改后的book. jsp创建一个定制的skeleton目录,并设置 JSP搜索路径属性, jsp.search.path: ., ../default。这样,当门户框架不能在当前目录下找到指定文件时,它就会尝试在默认的skeleton目录下去找。
这使得骨架的定制变得很简单。定制的骨架可以仅修改一个单独的骨架 JSP页面。该定制目录将只包含这一个文件,而其他的功能则依赖一个独立的骨架。
主题(Themes) 骨架和皮肤能共享一个公共的观感子集,也就是一个主题。主题为特殊门户组件使用不同样式和结构提供了一种机制,以便覆盖当前选择的观感。
Shell 门户的shell控制着门户原则功能部分的位置和对齐,以及任何附加的 内容窗口。大多数门户至少会显示一个页眉和一个页脚,但是shell可以被定制成以任何必要的方式包装主窗口。
布局(Layout)和占位符(placeholder) 门户的页面结构基于它的布局。布局是一种简单的表结构,用来把门户中的组件置入到称为占位符的独立单元中。当创建您自己的布局时,BEA会提供布局样式供您使用。这些样式会描述门户如何放置占位符。
布局由两个文件定义,一个是<layout_name>.layout文件,另一个是<layout_name>.html.txt文件。.layout文件是用于实际布局组件的XML文件。它就是包含着占位符的文件。而.html.txt文件仅仅是一个被Workshop和administration portal使用的模板。这些 工具把.html.txt文件当作一个模板,使 开发人员知道这个布局的效果,并为添加组件到占位符提供了方法。
菜单(Menus) 两个菜单之一可以在目录导航的门户中使用。这些菜单提供了稍微有点不同的导航级别。这些菜单 系统的缺省功能可以通过修改相关的skeleton文件来定制。
选择皮肤和骨架
尽管我提到观感(look-and-feel)文件会引用要使用的皮肤和骨架,但是这也不是必要条件。因为定义了皮肤和骨架名称以及路径的观感属性是可选的。那么如何才能使观感文件既不包含外观也不包含感觉呢?答案是无法做到。尝试不用容器来显示 内容,就好像尝试把水倒进一个虚构的玻璃杯中。假如观感文件中的一些或所有属性并没有被指定,那么框架就只有依赖于配置好的设置或用户默认的值。以下是选择皮肤和骨架的规则:
皮肤的命名:
- 如果没有指定,就使用/framework/skins/default皮肤。
皮肤的路径: - 如果没有指定,就使用/framework/skins/。
骨架的命名:
- 如果没有指定,就使用skin.properties中的default.skeleton.id。
- 如果没有指定default.skeleton.id属性,就使用/framework/skeletons/default。
- 如果没有指定,就使用skin.properties中的default.skeleton.path。
- 如果没有指定skin.properties中的default.skeleton.path,就使用/framework/skeletons/。
门户从选择的骨架中呈现出来。每个门户 XML组件会映射到一个骨架 JSP文件。骨架 JSP文件根据一个门户标签库来呈现这些组件。这个标签库就是门户骨架呈现标签库,它包含在render_taglib.jar中。知道库中所有可用标签的工作原理对理解门户的呈视过程和骨架定制很重要。用得最多的呈现标签是<render:beginRender>与<render:endRender>、<render:writeAttribute>,以及<render:renderChild>与<render:pageUrl>。
<render:beginRender>和<render:endRender>标签用于启动和结束一个门户组件的呈现过程。门户组件在层次上互相相关。例如,桌面包含顶级目录。而该目录又能包含任何数量的页面或子目录,子目录又可以包含自己的portlet、页面或者子目录。门户组件呈现就依据了这种层次结构。嵌套在门户 XML中的子组件被呈现在它们双亲的<render:beginRender>和 <render:endRender>标签之间。这两个标签包含了开放和封闭的HTML元素,而在这些元素中嵌套的组件会呈现它们自己的HTML。
<render:writeAttribute>标签要与<render:beginRender>标签一同使用。因为<render:beginRender>标签呈现了组件的开放HTML,而<render:writeAttribute>标签则添加属性到这个开放的HTML标签中。
带有子组件的组件,比如标题栏和标题栏按钮,用<render:renderChild>标签呈现这些子组件。
在呈现标签库中,标签可以用来创建URL。虽然这些标签在骨架呈现时很有用,但是它们实际上可以在应用 程序的任何必要的地方使用。
<render:pageUrl>标签用于生成一个能导航到特定页面或目录的URL,而<render:windowUrl>标签则是在指定了特定portel模式和/或状态的情况下,生成一个能导航到特定portel的URL。<render:resourceUrl>标签则用于为资源建立一个URL,比如 JavaScript文件或图像。要生成一个允许提交请求的URL,则要用到<render:postbackUrl>标签。
呈现顺序和过程
当定制一个现有的骨架或创建自己的骨架时,不仅理解骨架 JSP的呈现顺序非常重要,而且还要知道引用这些 JSP的频度。当一个组件被呈现时,就要引用到与它相关的骨架 JSP文件。在这个 JSP文件中,<render:beginRender>标签封装了所有的用于呈现该组件开放部分的逻辑。记住,门户组件是嵌套的,所有嵌套组件的骨架 JSP文件的<render:beginRender>部分是合为一体的。这个过程一直延续到最后嵌套的组件的<render:beginRender>部分被呈现为止。到那时,随着层次的上移,每个骨架 JSP文件再次被引用,而在此时就呈现位于<render:endRender>标签之间的 内容。由于这个原因,您会发现骨架 JSP文件中的大部分逻辑都是被封装在这些呈现标签中的。否则,每个组件的逻辑就会运行两次,而这种情况几乎不可能是我们想要的结果。
定制布局
BEA提供了三种布局样式,应该可以包括绝大多数需要的布局样式。然而,有时您还是需要创建定制布局,以获得缺省情况下未能提供的结构。要创建一个定制布局,首先需要复制一个.layout文件以及与它相关的.html.txt文件。
在.layout文件中,修改<netuix:layout>标签的适当属性,而把Layout 设置为markupType。然后添加并配置这个布局中可用的占位符。清单 1显示了一个拥有四个占位符的定制布局。还要注意,已经添加了占位符的width属性。这在后面会用于呈现门户中的HTML。
清单 1. 有时您需要创建定制布局,以获得缺省情况下未能提供的结构。这个定置布局包括四个占位符,并且已经添加了width属性。
<?xml version="1.0" encoding="UTF-8"?> <netuix:markupDefinition xmlns:netuix= "http://www.bea.com/servers/netuix/xsd/controls/ netuix/1.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ servers/netuix/xsd/controls/netuix/ 1.0.0 markup-netuix-1_0_0.xsd"> <netuix:locale language="en"/> <netuix:markup> <netuix:layout type="mainrightbar" title="Main and Right Bar Layout" description="Custom layout providing a main content window and three smaller windows on a right bar" htmlLayoutUri="/framework/markup/layout/ mainrightbar.html.txt"markupType= "Layout" markupName="mainrightbar"> <netuix:placeholder title="main" description="First placeholder in custom layout." markupType="Placeholder" markupName="main" width="75%"> </netuix:placeholder> <netuix:placeholder title="right_one" description="Second placeholder in custom layout." markupType="Placeholder" markupName="right_one" width="25%"> </netuix:placeholder> <netuix:placeholder title="right_two" description="Third placeholder in custom layout." markupType="Placeholder" markupName="right_two" width="25%"> </netuix:placeholder> <netuix:placeholder title="right_three" description="Fourth placeholder in custom layout." markupType="Placeholder" markupName="right_three" width="25%"> </netuix:placeholder> </netuix:layout> </netuix:markup> </netuix:markupDefinition> |
到这里,您应该已经明确您希望的定制布局看起来是什么样子。在.html.txt文件中,修改HTML以形成选择的表结构。务必要使定义在.layout文件中的占位符数与placeholderTD类的<td>标签数一致。清单 2显示了使用清单 1中布局的.html.txt文件。
清单 2. 在 html.txt 文件中,您可以修改HTML以形成表结构。本代码显示了在清单1 中使用的html.txt 文件。 <table class="portalLayout" id="thePortalLayout" width="100%" height="100%"> |
创建定制布局的最后一个步骤是创建一个支持定制布局的骨架JSP页面。该骨架JSP页面的名称需要与<netuix:layout> 标签的类型属性+ "layout.jsp"相匹配,除非设置了skeletonURI属性。skeletonURI属性允许您指定支持布局的骨架JSP文件的路径和文件名。否则,框架会试图用前面提到的方法在skeleton目录中寻找JSP页面。清单 3是支持定制布局的骨架JSP页面。
清单 3. 创建定制布局的最后一个步骤是创建一个支持定制布局的骨架JSP页面。下面是支持我们所创建布局的骨架JSP页面。 <%@ page import="com.bea.netuix.servlets. controls.layout.PlaceholderPresentationContext, com.bea.netuix.servlets.controls.layout. LayoutPresentationContext, java.util.List" %> <%@ taglib uri="render.tld" prefix="render" %> |
定制菜单
门户中的菜单组件也可以基于align属性来支持定制。它能够以三种对齐方式来实现呈现目录标签的定制骨架:左、中、右。您可以对BEA提供的任何默认骨架进行修改。但是,由于这是基本骨架JSP文件,任何对门户的未来升级都会潜在地导致覆盖已修改的JSP文件。出于这个原因,最好还是使用定制骨架。
定制骨架可以通过复制门户中的任何可用骨架来创建。只需简单地复制整个默认骨架、重命名,然后做您想做的修改。我更愿意定制骨架只包含修改后的骨架JSP,并允许框架为任何遗留的JSP使用默认的目录。
我们正在讨论的修改了对齐方式的JSP页面是singlelevelmenu.jsp。清单 4 显示了这个修改后的JSP页面。
清单 4. 要创建定制菜单,您可以修改BEA提供的任何缺省骨架。简单地复制整个默认骨架、重命名,然后做您想做的修改。我们正在讨论的修改了对齐方式的JSP页面是singlelevelmenu.jsp。下面是修改后的JSP页面。 <%@ page import="com.bea.netuix.servlets.controls.
window.WindowPresentationContext, com.bea.netuix.servlets.controls.window. TitlebarPresentationContext, java.util.Iterator, com.bea.netuix.servlets.controls.page. PagePresentationContext, com.bea.netuix.servlets.controls.page. BookPresentationContext, com.bea.netuix.servlets.controls.page. MenuPresentationContext, com.bea.netuix.servlets.controls. PresentationContext, java.util.List, com.bea.netuix.servlets.controls.window. WindowCapabilities" %> <%@ page session="false"%> <%@ taglib uri="render.tld" prefix="render" %> <%! static final String BOOK_CLASS = "bea-portal-book"; static final String MENU_CLASS = BOOK_CLASS + "-menu-single"; static final String MENU_CONTAINER_CLASS = MENU_CLASS + "-container"; static final String MENU_ITEM_CLASS = MENU_CLASS + "-item"; static final String MENU_ITEM_ACTIVE_CLASS= MENU_ITEM_CLASS + "-active"; static final String MENU_BUTTONS_CLASS = MENU_ITEM_CLASS + "-buttons"; static final String DESKTOP_BOOK_CLASS = "bea-portal-book-primary"; static final String DESKTOP_MENU_CLASS = DESKTOP_BOOK_CLASS + "-menu-single"; static final String DESKTOP_MENU_CONTAINER_CLASS = DESKTOP_MENU_CLASS + "-container"; static final String DESKTOP_MENU_ITEM_CLASS = DESKTOP_MENU_CLASS + "-item"; static final String DESKTOP_MENU_ITEM_ACTIVE_CLASS = DESKTOP_MENU_ITEM_CLASS + "-active"; static final String DESKTOP_MENU_BUTTONS_CLASS = DESKTOP_MENU_ITEM_CLASS + "-buttons"; %>
<% BookPresentationContext book = BookPresentationContext. getBookPresentationContext(request); MenuPresentationContext menu = MenuPresentationContext. getMenuPresentationContext(request); String align = menu.getAlign(); if (align == null) { align = "left"; }
String menuContainerClass = MENU_CONTAINER_CLASS; String menuClass = MENU_CLASS; String menuItemClass = MENU_ITEM_CLASS; String menuItemActiveClass = MENU_ITEM_ACTIVE_CLASS; String menuButtonsClass = MENU_BUTTONS_CLASS;
if (book.isDesktopBook()) { menuClass = DESKTOP_MENU_CLASS; menuContainerClass = DESKTOP_MENU_CONTAINER_CLASS; menuItemClass = DESKTOP_MENU_ITEM_CLASS; menuItemActiveClass = DESKTOP_MENU_ITEM_ACTIVE_CLASS; menuButtonsClass = DESKTOP_MENU_BUTTONS_CLASS; }
List children = menu.getChildren(); %>
<render:beginRender> <%-- Begin Single Level Menu --%> <div class="bea-portal-ie-table-buffer-div" align=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%=align%>"> <table border="0" cellpadding="0" cellspacing="0" width="100%"> <tr> <td class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuContainerClass %>" nowrap="nowrap"> <ul <render:writeAttribute name="id" value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menu.getPresentationId() %>"/> <render:writeAttribute name="class" value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menu.getPresentationClass() %>" defaultValue=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuClass %>"/> <render:writeAttribute name="style" value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menu.getPresentationStyle() %>"/> ><%
// Only render tabs when in view mode if (book.getWindowMode(). equals(WindowCapabilities.VIEW)) {
Iterator pages = book.getPagePresentationContexts(). iterator();
while (pages.hasNext()) { PagePresentationContext pageCtx = (PagePresentationContext) pages.next(); String activeImage = pageCtx.getActiveImage(); String inactiveImage = pageCtx.getInactiveImage(); String rolloverImage = pageCtx.getRolloverImage();
if (!pageCtx.isHidden() && pageCtx.isVisible()) { if (pageCtx.isActive()) { if (activeImage == null) { %><li class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuItemActiveClass %>"><span><%= pageCtx.getTitle() %></span></li><% } else if (rolloverImage == null) { %><li class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuItemActiveClass %>"><span><img src=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= activeImage %>"></span></li><% } else { %><li class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuItemActiveClass %>"><span><img src= /A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= activeImage %>" longDesc=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= rolloverImage %>"> </span></li><% } } else { if (inactiveImage == null) { %><li class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuItemClass %>"> <a href="<render:pageUrl pageLabel=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= pageCtx.getDefinitionLabel() %>"/>"><%= pageCtx.getTitle() %></a></li><% } else if (rolloverImage == null) { %><li class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuItemClass %>"> <a href="<render:pageUrl pageLabel=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= pageCtx.getDefinitionLabel() %>"/>"><img src=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= inactiveImage %>"></a></li><% } else { %><li class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuItemClass %>"> <a href="<render:pageUrl pageLabel=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= pageCtx.getDefinitionLabel() %>"/>"><img src=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= inactiveImage %>" longDesc=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= rolloverImage %>"></a></li><% } } } } } %> </ul> </td> <% if (children != null && children.size() > 0) { %> <td class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= menuButtonsClass %>" align="right" nowrap="nowrap"> <% } %> </render:beginRender> <render:endRender> <% if (children != null && children.size() > 0) { %> </td> <% } %> </tr> </table> </div> <%-- End Single Level Menu --%> </render:endRender> |
下一步就是创建能在XML中指定align属性而并不修改现有singlelevel.menu文件的菜单组件。通过创建单独的菜单,我们就不会把自己限制到必须使用单一对齐方式的单个菜单。
要创建一个新菜单,首先要复制singlelevel.menu。然后改变标题、描述和markupName以满足您的需要,并且添加一个align属性。
清单 5. 要创建一个新菜单,首先要复制singlelevel.menu。然后改变标题、描述和markupName以满足您的需要,并且添加一个align属性。下面是一个右对齐的单级菜单。 <?xml version="1.0" encoding="UTF-8"?>
<netuix:markupDefinition xmlns:netuix= "http://www.bea.com/servers/netuix/xsd/controls/ xmlns:xsi="http://www.w3.org/2001/ XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/servers/ 1_0_0.xsd"> <netuix:locale language="en"/> <netuix:markup> <netuix:singleLevelMenu title="Single Level Right Menu" description="This menu provides a single level of tabs, right aligned, used to navigate across pages." markupType="Menu" markupName= "singleLevelRightMenu" align="right"/> </netuix:markup> </netuix:markupDefinition>
|
要使用新创建的定制骨架,可以创建一个观感(look-and-feel)文件,以便将这个骨架与所选择的皮肤相关联。观感文件很容易创建和管理。在Workshop中,当编辑一个.portal文件时,可以从File Menu中选择Portal ' Manage Look And Feel Properties。
定制Shell
Web设计人员通常会倾向于使用左侧导航栏提供给用户一个集中的导航结构。左侧导航栏,或与之类似的导航栏,可以添加到一个定制shell中。Shell不一定只包含页眉和页脚。清单 6显示了一个提供页眉、页脚和一个左侧导航栏的shell例子。
清单 6. 您可以在定制shell中添加导航栏。下面是一个提供页眉、页脚和一个左侧导航栏的shell例子。 <?xml version="1.0" encoding="UTF-8"?> <netuix:markupDefinition xmlns:netuix="http://www.bea.com/servers/netuix/ xmlns:html="http://www.w3.org/1999/xhtml- netuix-modified/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema- xsi:schemaLocation="http://www.bea.com/servers/ 1_0_0.xsd"> <netuix:locale language="en"/> <netuix:markup> <netuix:shell title="Left Navigation Shell" description= "A header, footer and left navigation pane included in this shell." markupType="Shell" markupName="leftNavigation"> <netuix:head/> <netuix:header/> <html:table style="vertical-align: top; width: 100%;"> <html:tr> <html:td style="vertical-align: top; width: 1%;" valign="top"> <netuix:jspContent contentUri= "/framework/markup/shell/support/ leftnavigation.jsp"/> </html:td> <html:td style="vertical-align: top;
<netuix:break/> </html:td> </html:tr> </html:table> <netuix:footer/> </netuix:body> </netuix:shell> </netuix:markup> </netuix:markupDefinition>
|
清单 6中的定制shell是通过复制教程门户中的leftPaneHeaderFooter.shell来创建的。选择<html:td>标签后,也可以同样地创建一个右侧导航栏shell。<netuix:break>标签则能呈现门户内容。
在<netuix:jspContent>标签中,会使用到一个leftnavigation.jsp。这个JSP页面是在shell/support目录下创建的,因为这个修改并不是针对骨架的。该JSP页面使用可用的PresentationContexts来显示模拟Main Book的一列链接。请参见清单 7。
清单 7. 在 清单 6中,会引用到一个leftnavigation.jsp。这个JSP页面是在shell/support目录下创建的,因为这个修改并不是针对骨架的。该JSP页面使用可用的PresentationContexts来显示模拟Main Book的一列链接。 <?xml version="1.0" encoding="UTF-8"?> <netuix:markupDefinition xmlns:netuix="http://www.bea.com/servers/netuix/ xmlns:html="http://www.w3.org/1999/xhtml- netuix-modified/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema- xsi:schemaLocation="http://www.bea.com/servers/ 1_0_0.xsd"> <netuix:locale language="en"/> <netuix:markup> <netuix:shell title="Left Navigation Shell" description= "A header, footer and left navigation pane included in this shell." markupType="Shell" markupName="leftNavigation"> <netuix:head/> <netuix:header/> <html:table style="vertical-align: top; width: 100%;"> <html:tr> <html:td style="vertical-align: top; width: 1%;" valign="top"> <netuix:jspContent contentUri= "/framework/markup/shell/support/ leftnavigation.jsp"/> </html:td> <html:td style="vertical-align: top;
<netuix:break/> </html:td> </html:tr> </html:table> <netuix:footer/> </netuix:body> </netuix:shell> </netuix:markup> </netuix:markupDefinition>
|
定制皮肤和骨架
显示清单 7中的链接的JSP页面要使用一些CSS样式。由于我们无法确定最后会使用哪种观感,因此我通过创建一个额外的CSS并在skin_custom.properties文件中引用它来扩展缺省的皮肤。另外,这也保证了以后的升级不会覆盖我的实现代码。
我们已经谈到了骨架JSP的较小修改,然而,要定制到何种程度并没有什么限制。例如,门户组件有一个orientation属性。该属性为对齐标题栏组件呈现的地点提供了一种机制。您可以实现一个骨架,支持标题栏呈现到portlet内容窗口的四条边之一:顶边、右边、底边或左边。清单 8显示了一个支持顶边和底边方向的定制window.jsp例子。
清单 8. 可以实现一个骨架来支持标题栏呈现到portlet内容窗口的四条边之一:顶边、右边、底边或左边。下面是一个支持顶边和底边方向的定制window.jsp例子。 <%@ page import="com.bea.netuix.servlets.>%& >%&controls.PresentationContext"%>>%& <%@ page import="com.bea.netuix.servlets.controls.>%& >%&application.DesktopPresentationContext"%>>%& <%@ page import="com.bea.netuix.servlets.controls.>%& >%&page.BookPresentationContext"%>>%& <%@ page import="com.bea.netuix.servlets.controls.>%& >%&page.PagePresentationContext"%>>%& <%@ page import="com.bea.netuix.servlets.controls.>%& >%&window.WindowPresentationContext"%>>%& <%@ page import="com.bea.netuix.servlets.manager.>%& >%&AppContext"%>>%& <%@ page import="com.bea.portlet.PageURL"%>>%& >%& <table class="leftnav-table">>%& <%>%& >%&AppContext appCtx = >%& >%&AppContext.getAppContext(request);>%& >%&DesktopPresentationContext desktopCtx = >%& >%&DesktopPresentationContext.>%& >%&getDesktopPresentationContext(request);>%& >%&BookPresentationContext bookCtx = >%& >%&desktopCtx.getBookPresentationContext();>%& >%& >%&PagePresentationContext childCtx = null;>%& >%& >%&List bookChildren = >%& >%&bookCtx.getPagePresentationContexts();>%& >%& >%&for (Iterator i = bookChildren.iterator(); >%& >%&i.hasNext();) {>%& >%&childCtx = (PagePresentationContext) i.next();>%& >%&String style = "leftnav-page";>%& >%&if (childCtx.isActive()) {>%& >%&style = "leftnav-page-active";>%& >%&}>%& >%& %>>%& >%&<tr>>%& >%&<td class=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%=style%>" nowrap>>%& >%&<a href=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%=PageURL.createPageURL(>%& >%&request, response, >%& >%&childCtx.getDefinitionLabel()).>%& >%&toString()%>"><%=childCtx.getTitle()%>>%& >%&</a></td>>%& >%&</tr>>%& <%>%& >%&}>%& %>>%& </table>>%& >%& >%& >%& >%& >%& <%@ page import="com.bea.netuix.servlets.controls.>%& >%&portlet.PortletPresentationContext"%>>%& <%@ page import="com.bea.netuix.servlets.controls.>%& >%&window.WindowPresentationContext,>%& >%&com.bea.netuix.servlets.controls.window.>%& >%&TitlebarPresentationContext, >%& >%&java.util.List,>%& >%&java.util.Iterator, >%& >%&com.bea.netuix.servlets.controls.page.>%& >%&BookPresentationContext,>%& >%&com.bea.netuix.servlets.controls.window.>%& >%&WindowCapabilities">%& %>>%& <%@ page session="false"%>>%& <%@ taglib uri="render.tld" prefix="render" %>>%& >%& <%>%& >%&WindowPresentationContext window = >%& >%&WindowPresentationContext.>%& >%&getWindowPresentationContext(request);>%& >%&TitlebarPresentationContext titlebar = >%& >%&(TitlebarPresentationContext) >%& >%&window.getFirstChild("window:titlebar");>%& >%&boolean onBottom=false;>%& >%& >%&if (window instanceof PortletPresentationContext) {>%& >%&String orientation = ((>%& >%&PortletPresentationContext)window).>%& >%&getOrientation();>%& >%&onBottom = ((orientation != null) && >%& >%&(orientation.equals("3")));>%& >%&}>%& >%&if (titlebar != null) {>%& >%&titlebar.setVisible(!onBottom);>%& >%&}>%& >%&boolean isMinimized = >%& >%&window.getWindowState().equals(>%& >%&WindowCapabilities.MINIMIZED);>%& %>>%& <render:beginRender>>%& <%>%& >%&final String expandWidth = "100%";>%& %>>%& >%& >%& >%&<%-- Begin Window --%>>%& >%&<div>%& >%&<render:writeAttribute name="id" value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= >%& >%&window.getPresentationId() %>"/>>%& >%&<render:writeAttribute name="class" >%& >%&value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= window.getPresentationClass() >%& >%&%>" defaultValue="bea-portal-window"/>>%& >%&<render:writeAttribute name="style" value=>%& >%&/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= window.getPresentationStyle() %>"/>>%& >%&<render:writeAttribute name="width" >%& >%&value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= window.isPacked() ? null : >%& >%&expandWidth %>"/>>%& >%&>>%& <<%>%& >%&if (!onBottom) {>%& %>>%& >%&<render:renderChild presentationContext=>%& >%&/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= titlebar %>"/>>%& <<%>%& >%&}>%& %>>%& <>%& >%&<%-- Begin Window Content --%>>%& >%&<% if (! isMinimized )>%& >%&{>%& >%&%><div>%& >%&<render:writeAttribute name="class" >%& >%&value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= window.>%& >%&getContentPresentationClass() %>" >%& >%&defaultValue="bea-portal-window->%& >%&content"/>>%& >%&<render:writeAttribute name="style" >%& >%&value=/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= window.>%& >%&getContentPresentationStyle() %>" />>%& >%&><%>%& >%&}>%& %>>%& >%&</render:beginRender>>%& >%&<render:endRender>>%& <>%& >%&<% if (! isMinimized )>%& >%&{>%& >%&%></div><%>%& >%&}>%& >%&if (titlebar != null) {>%& >%&titlebar.setVisible(onBottom);>%& >%&}>%& >%&if (onBottom) {>%& %>>%& >%&<render:renderChild presentationContext=>%& >%&/A-A-B/2005/08/10/200508101649187_1./A-A-B/2005/08/10/200508101649185_2."<%= titlebar %>"/>>%& <>%& <<%>%& >%&}>%& %>>%& >%&</div>>%& <<%-- End Window --%>>%& </render:endRender>>%&
|
既然已经开发了这么多行代码,让我们来看看已经完成的结果吧。图 1显示了一个门户例子,其中使用到缺省的观感。
图 1.
这个示例门户使用了缺省的观感,它通过定制的样式显示shell 导航。
您觉得我们做的工作比这个多吗?我们确实做了很多。记住,我们的大部分定制都是在默认观感之外创建的,因为我们想要修改基本功能。图 2中显示的是一个使用了我们所有定制观感的相同门户。
图 2.
这个门户与显示在图 1中的门户相同,但它使用合并了我们所有修改的观感。
好了,完成了。我们并没有做所有的事。我只是添加了一个页眉和页脚,调节了CSS文件中的颜色和边框。除此之外,代码都是一样的。
BEA Portal UI Framework使开发人员和管理员能够以他们觉得合适的方法定制一个门户。对定制的唯一限制是您的想像力,或许还有您的艺术功底。
关于作者
David Hritz是NuWave Solutions, LLC的CTO。他还是Creating Web Portals with BEA WebLogic (March 2003)一书的合著者。您可以通过dhritz@nuwavesolutions.com联系它。