上几篇开发的Button和TextBox组件,一直采用的是claro皮肤,代码是固定写死的:
@ResourceDependency(library = "dijit/themes/claro", name = "claro.css", target = "head") })
<body class="claro">
因为所有的组件都存在换肤需要,所以在继续开发更多组件以前,我先解决换肤问题。上一篇实现了自定义<h:head>以后,换肤就好办了,只需要<head>中加入换皮肤所需的css,并在页面加载时设置body的class,就可以实现换肤了。
修改HeadRenderer.java
package org.dojo4j.component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@FacesRenderer(componentFamily = Head.COMPONENT_FAMILY, rendererType = Head.COMPONENT_TYPE)
//直接继承com.sun.faces.renderkit.html_basic.HeadRenderer,修改部分渲染代码
public class HeadRenderer extends com.sun.faces.renderkit.html_basic.HeadRenderer {
public static final String THEME_KEY = "dojo4j.theme";
public static final String DEFAULT_THEME = "claro";
private String theme = null;
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
ResponseWriter writer = context.getResponseWriter();
//加入dojo.css引用,因为每个dojo组件都需要dojo.css支持,所以加到head里避免重复生成
writer.startElement("link", component);
writer.writeAttribute("type", "text/css", null);
writer.writeAttribute("rel", "stylesheet", null);
writer.writeAttribute("href", request.getContextPath() + context.getExternalContext().getRequestServletPath()
+ "/javax.faces.resource/dojo/resources/dojo.css", null);
writer.endElement("link");
//加入皮肤.css引用
this.theme = getTheme(context);
writer.endElement("link");
writer.startElement("link", component);
writer.writeAttribute("rel", "stylesheet", null);
writer.writeAttribute("href", request.getContextPath() + context.getExternalContext().getRequestServletPath()
+ "/javax.faces.resource/dijit/themes/" + this.theme + "/" + this.theme + ".css", null);
writer.endElement("link");
//加入dojo.js引用,因为每个dojo组件都需要dojo.js支持,所以加到head里避免重复生成
writer.startElement("script", component);
writer.writeAttribute("type", "text/javascript", null);
writer.writeAttribute("src", request.getContextPath() + context.getExternalContext().getRequestServletPath()
+ "/javax.faces.resource/dojo/dojo.js", null);
writer.writeAttribute("data-dojo-config", "async: true, parseOnLoad: true", null);
writer.endElement("script");
encodeHeadResources(context, component);
writer.endElement("head");//writer.startElement("head");在父类的encodeBegin里
}
//获取皮肤参数并设置到cookie中
public static String getTheme(FacesContext context) {
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
String theme = request.getParameter(THEME_KEY);
if (theme == null || theme.trim().length() < 1) {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (int i=0;i<cookies.length;i++) {
Cookie cookie = cookies[i];
if (THEME_KEY.equals(cookie.getName())) {
theme = cookie.getValue();
break;
}
}
}
}
if (theme == null || theme.trim().length() < 1) {
theme = DEFAULT_THEME;
}
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
response.addCookie(new Cookie(THEME_KEY, theme));
return theme;
}
private void encodeHeadResources(FacesContext context, UIComponent component) throws IOException {
ResponseWriter writer = context.getResponseWriter();
List<String> requires = new ArrayList<String>();
//require加入必需的dojo/parser
requires.add("dojo/parser");
//解决皮肤切换需求
requires.add("dojo/dom-class");
UIViewRoot viewRoot = context.getViewRoot();
for (UIComponent resource : viewRoot.getComponentResources(context, "head")) {
Map<String, Object> attributes = resource.getAttributes();
String name = (String) attributes.get("name");
//把引用的dojo库中的js文件,转换成require写法,不引入js文件
if (name.startsWith("dojo/") || name.startsWith("dijit/") || name.startsWith("dojox/")) {
if (name.endsWith(".js")) {
String path = name.substring(0, name.lastIndexOf("."));
if (!requires.contains(path))
requires.add(path);
continue;
}
}
resource.encodeAll(context);
}
//生成dojo require方式的代码
writer.startElement("script", component);
writer.write("require([");
String tmp = "";
for (int i = 0; i < requires.size(); i++) {
writer.write(tmp + "\"" + requires.get(i) + "\"");
tmp = ", ";
}
解决皮肤切换需求
writer.write(", \"dojo/domReady!\"], function(parser, domClass) {");
writer.write("domClass.add(document.body, \"" + this.theme + "\");");
writer.write("});");
writer.endElement("script");
}
}
删除ButtonRenderer.java和TextBoxRenderer.java中的代码:
@ResourceDependency(name = "dijit/themes/claro/claro.css", target = "head"),
将buttonTest.xhtml和textBoxTest.xhtml中的<body class="claro">改成<body>
这样改了以后,在首次访问页面时,会加载默认皮肤claro,可以通过在请求中加入dojo4j.theme=xxx改变皮肤,改了以后会保存在cookie中,持续有效。目前dojo提供的皮肤有四种:claro,tundra,soria,nihilo
查看生成的页面源代码可以看到发生的变化:
<link rel="stylesheet" href="/dojo4j/faces/javax.faces.resource/dijit/themes/tundra/tundra.css" />
<script>
require([ "dojo/parser", "dojo/dom-class", "dijit/form/TextBox",
"dijit/form/Button", "dojo/domReady!" ],
function(parser, domClass) {
domClass.add(document.body, "tundra");
});
</script>
下载代码