目标:Ofbiz皮肤完全自主定制;
前提:已经创建hello工程,针对hello应用进行定制开发;
注意:完成自主定制皮肤只针对具体应用。如果需要定制通用皮肤,header与footer可以完全定制,但左侧菜单与内容区域定制会受到较大的局限。
hello应用目录结构;
与kadmin主题目录结构:
分析:皮肤主题的开发与定制主要在themes/*下完成,但如果想完全自主定义,如二级菜单或者是内容显示区域,侧需要配合具体应用来完成。以下步骤先从themes目录下进行操作也定制;
定制要点:
1、从themes目录下复制一个主题重全名为kadmin;
2、修改kadmin/ofbiz-component.xml内容;
<ofbiz-component name="kadmin"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-component.xsd">
<!-- define resource loaders; most common is to use the component resource loader -->
<resource-loader name="main" type="component"/>
<!-- entity resources: model(s), eca(s), group, and data definitions -->
<entity-resource type="data" reader-name="seed" loader="main" location="data/kadminThemeData.xml"/>
<!-- web applications; will be mounted when using the embedded Jetty container -->
<webapp name="kadmin"
title="Kadmin"
menu-name="secondary"
server="default-server"
location="webapp/kadmin"
mount-point="/kadmin"
app-bar-display="false"/>
</ofbiz-component>
3、重命名kadmin/data/中的文件为KadminThemeData.xml
<entity-engine-xml>
<VisualTheme visualThemeId="KADMIN" visualThemeSetId="BACKOFFICE" description="It's bizzness, it's bizzness time. I couldn't have said it better myself. This theme gets down"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_NAME" resourceValue="KADMIN" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_STYLESHEET" resourceValue="/bizznesstime/css/style.css" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_HELPSTYLESHEET" resourceValue="/bizznesstime/css/help.css" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_DOCBOOKSTYLESHEET" resourceValue="/bizznesstime/webapp/bizznesstime/css/docbook.css" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_HDR_JAVASCRIPT" resourceValue="/bizznesstime/js/application.js" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_SHORTCUT_ICON" resourceValue="/images/ofbiz.ico" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_HDR_IMAGE_URL" resourceValue="/images/ofbiz_logo.gif" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_HDR_TMPLT_LOC" resourceValue="component://bizznesstime/includes/header.ftl" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_FTR_TMPLT_LOC" resourceValue="component://bizznesstime/includes/footer.ftl" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_NAV_TMPLT_LOC" resourceValue="component://bizznesstime/includes/appbar.ftl" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_MSG_TMPLT_LOC" resourceValue="component://bizznesstime/includes/messages.ftl" sequenceId="01"/>
<VisualThemeResource visualThemeId="KADMIN" resourceTypeEnumId="VT_SCREENSHOT" resourceValue="/bizznesstime/screenshot.jpg" sequenceId="01"/>
</entity-engine-xml>
这是一个资源文件,大体内容定义了包括主题的名称、类型、样式、脚本及flt模板文件。这些内容将在程序运行后写入到数据库visual_theme、visual_theme_resource、visual_theme_set三个表中,程序运行之后,将会读取数据库表的的对应信息,添加到页面中,如下所示:
( 注:sequenceId 的作用是针对 resourceTypeEnumId 的类型为同类型加以区分; 例 XML中如果有两个
resourceTypeEnumId=”VT_STYLESHEET”则其中一个的sequenceId=”01”则另一个为sequenceId=”02”)
2):includes
该文件夹主要包含该主题页面的头部,尾部,一级菜单,消息和关闭头部文件的 FTL;其中修改主题的页面都在这里修
改 。
4、打开header.flt文件,会看类似下面的语句<#if (requestAttributes.person)??><#assign person = requestAttributes.person></#if>,这是freemark标记语言,先略过,接下来下半部分会看到类似
<body>
<div id="wrapper">
……
这样的语句,这样相信很熟悉了,这是一个html页面定义的开始部分。接着往下看,会发现,这些body标签并没有关闭,开始觉得奇怪,但想想,这是一个头部的模块,还有其它部分的模块还没有加载完成,就明白了。细看header.ftl与footer.ftl与appbar.ftl代码,发现这些代码都可以完全自定义,可以使用自定义的样式与脚本实现不同效果。改着改着,发现问题来了,没找到menu与content的定义文件!看下图:
是的,在themes目录里没找到menu的定义ftl文件,因为不在这里定义,如果需要定义,只能对具体应用进行定义,不能对全部应用进行统一定义。
5、移步到具体应用程序文件夹hot-deploy/hello/widget/hello/CommonScreens.xml
我们已经知道main-decorator是主装饰模块,actions配置节是模块设置,widgets里是配置装饰器,我们在component://common/widget/CommonScreens.xml中找到GlobalDecorator的定义文件。其中有一段是这样的:
<!-- render appheader: both menu widget style and ftl template style menus are supported-->
<section name="Render-App-Nav">
<condition>
<not>
<if-empty field="userLogin" />
</not>
</condition>
<widgets>
<section>
<condition>
<not>
<if-empty field="appheaderTemplate" />
</not>
</condition>
<widgets>
<platform-specific>
<html>
<html-template location="${appheaderTemplate}" />
</html>
</platform-specific>
</widgets>
<fail-widgets>
<section>
<condition>
<not>
<if-empty field="parameters.applicationTitle" />
</not>
</condition>
<widgets>
<label style="apptitle">${parameters.applicationTitle}</label>
</widgets>
</section>
<section>
<condition>
<not>
<if-empty field="applicationMenuLocation" />
</not>
</condition>
<widgets>
<include-menu name="${applicationMenuName}" location="${applicationMenuLocation}" />
</widgets>
</section>
</fail-widgets>
</section>
</widgets>
<fail-widgets>
<!-- better to just not include this, the CommonAppBarMenu doesn't show anything by default if the user isn't logged in, causing a funny empty menu: <include-menu name="CommonAppBarMenu" location="component://common/widget/CommonMenus.xml"/> -->
</fail-widgets>
</section>
看其中这段:
<condition>
<not>
<if-empty field="appheaderTemplate" />
</not>
</condition>
这段表示如果存在appheaderTemplate这个配置节,就执行<widgets>中的内容,如果不存在,就执行<fail-widgets>中的内容,那么这个 appheaderTemplate是什么东西呢?请看上面截图红框部分。在这里是注释掉的,即这个appheaderTemplate是不存在的,那么自然是执行<fail-widgets>里的内容。接着往下看,这里面又有一个配置是这样的:
<condition>
<not>
<if-empty field="applicationMenuLocation" />
</not>
</condition>
意思是说,如果存在applicationMenuLocation,则执行下面这段,
<widgets>
<include-menu name="${applicationMenuName}" location="${applicationMenuLocation}" />
</widgets>
通过查找,发现 applicationMenuLocation指的就是具体的应用中CommonScreens.xml里配置的applicationMenuLocation,路径是component://hello/widget/hello/HelloMenus.xml,即左边菜单;通过这样去分析,返回去想,如果把截图中红框的注释取消,那是不是就可以自定义它的菜单部分呢?正确。但这里有个问题,即菜单是写死的,不能通过程序界面配置,但想想,ofbiz本身应用的菜单配置都是写死的,也无妨。
本篇结束