實現基於FTL模板的選單之一
思路是通過在java 程式碼中生成對ftl巨集的呼叫。然後在ftl模板中定義這些巨集即可。最後讓OFBIZ載入我們的選單模板即可。
首先們需要建立一個建一個新的類並且實現MenuStringRenderer。這個類就叫作 MacroMenuRenderer 吧。
實現的程式碼可以是如下。
/**
* Widget Library - Form Renderer implementation based on Freemarker macros
*
*/
public class MacroMenuRenderer implements MenuStringRenderer {
public static final String module = MacroTreeRenderer.class.getName();
protected HttpServletRequest request;
protected String userLoginIdAtPermGrant;
protected boolean userLoginIdHasChanged = true;
private Template macroLibrary;
private WeakHashMap<Appendable, Environment> environments = new WeakHashMap<Appendable, Environment>();
protected boolean widgetCommentsEnabled = false;
public MacroMenuRenderer(String macroLibraryPath, Appendable writer,HttpServletRequest request) throws TemplateException, IOException {
this.macroLibrary = FreeMarkerWorker.getTemplate(macroLibraryPath);
this.request = request;
}
private void executeMacro(Appendable writer, String macro) throws IOException {
try {
Environment environment = getEnvironment(writer);
Reader templateReader = new StringReader(macro);
// FIXME: I am using a Date as an hack to provide a unique name for the template...
Template template = new Template((new java.util.Date()).toString(), templateReader, FreeMarkerWorker.getDefaultGorun8Config());
templateReader.close();
environment.include(template);
} catch (TemplateException e) {
Debug.logError(e, "Error rendering screen macro [" + macro + "] thru ftl", module);
} catch (IOException e) {
Debug.logError(e, "Error rendering screen macro [" + macro + "] thru ftl", module);
}
}
private void executeMacro(Appendable writer, String macroName, Map<String, Object> parameters) throws IOException {
StringBuilder sb = new StringBuilder("<@");
sb.append(macroName);
if (parameters != null) {
for (Map.Entry<String, Object> parameter : parameters.entrySet()) {
sb.append(' ');
sb.append(parameter.getKey());
sb.append("=");
Object value = parameter.getValue();
if (value instanceof String) {
sb.append('"');
sb.append(((String) value).replaceAll("\"", "\\\\\""));
sb.append('"');
} else {
sb.append(value);
}
}
}
sb.append(" />");
executeMacro(writer, sb.toString());
}
private Environment getEnvironment(Appendable writer) throws TemplateException, IOException {
Environment environment = environments.get(writer);
if (environment == null) {
Map<String, Object> input = UtilMisc.toMap("key", null);
environment = FreeMarkerWorker.renderTemplate(macroLibrary, input, writer);
environments.put(writer, environment);
}
return environment;
}
public void renderFormatSimpleWrapperRows(Appendable writer, Map<String, Object> context, Object menuObj) throws IOException {
List<ModelMenuItem> menuItemList = ((ModelMenu) menuObj).getMenuItemList();
for (ModelMenuItem currentMenuItem: menuItemList) {
renderMenuItem(writer, context, currentMenuItem);
}
}
public void renderMenuItem(Appendable writer, Map<String, Object> context, ModelMenuItem menuItem) throws IOException {
//Debug.logInfo("in renderMenuItem, menuItem:" + menuItem.getName() + " context:" + context ,"");
boolean hideThisItem = isHideIfSelected(menuItem, context);
if (hideThisItem)
{
return;
}
String style = menuItem.getWidgetStyle();
if (menuItem.isSelected(context)) {
style = menuItem.getSelectedStyle();
if (UtilValidate.isEmpty(style)) {
style = "selected";
}
}
String name = menuItem.getName();
if (menuItem.getDisabled() || this.isDisableIfEmpty(menuItem, context)) {
style = menuItem.getDisabledTitleStyle();
}
String alignStyle = menuItem.getAlignStyle();
String toolTip = menuItem.getTooltip(context);
Link link = menuItem.getLink();
StringWriter sr = new StringWriter();
sr.append("<@renderMenuItemOpen ");
sr.append(" style=\"");
sr.append(style);
sr.append("\" alignStyle=\"");
sr.append(alignStyle);
sr.append("\" toolTip=\"");
sr.append(toolTip);
sr.append("\" name=\"");
sr.append(name);
sr.append("\" />");
// executeMacro(writer, sr.toString());
if (link != null) {
renderLink(writer, context, link);
} else {
String txt = menuItem.getTitle(context);
StringUtil.SimpleEncoder simpleEncoder = (StringUtil.SimpleEncoder) context.get("simpleEncoder");
if (simpleEncoder != null) {
txt = simpleEncoder.encode(txt);
}
//sr = new StringWriter();
sr.append("<@renderMenuItemText ");
sr.append(" text=\"");
sr.append(txt);
sr.append("\" />");
//executeMacro(writer, sr.toString());
}
if (!menuItem.getMenuItemList().isEmpty()) {
//sr = new StringWriter();
sr.append("<@renderSubMenuOpen/> ");
// executeMacro(writer, sr.toString());
for (ModelMenuItem childMenuItem : menuItem.getMenuItemList()) {
childMenuItem.renderMenuItemString(writer, context, this);
}
//sr = new StringWriter();
sr.append("<@renderSubMenuClose/>");
//executeMacro(writer, sr.toString());
}
//sr = new StringWriter();
sr.append("<@renderMenuItemClose/>");
executeMacro(writer, sr.toString());
}
public boolean isDisableIfEmpty(ModelMenuItem menuItem, Map<String, Object> context) {
boolean disabled = false;
String disableIfEmpty = menuItem.getDisableIfEmpty();
if (UtilValidate.isNotEmpty(disableIfEmpty)) {
List<String> keys = StringUtil.split(disableIfEmpty, "|");
for (String key: keys) {
Object obj = context.get(key);
if (obj == null) {
disabled = true;
break;
}
}
}
return disabled;
}
/**
* Renders the beginning boundary comment string.
* @param writer The writer to write to
* @param widgetType The widget type: "Screen Widget", "Form Widget", etc.
* @param modelWidget The widget
*/
public void renderBeginningBoundaryComment(Appendable writer, String widgetType, ModelWidget modelWidget) throws IOException {
if (this.widgetCommentsEnabled) {
StringWriter sr = new StringWriter();
sr.append("<@formatBoundaryComment ");
sr.append(" boundaryType=\"");
sr.append("Begin");
sr.append("\" widgetType=\"");
sr.append(widgetType);
sr.append("\" widgetName=\"");
sr.append(modelWidget.getBoundaryCommentName());
sr.append("\" />");
executeMacro(writer, sr.toString());
}
}
/**
* Renders the ending boundary comment string.
* @param writer The writer to write to
* @param widgetType The widget type: "Screen Widget", "Form Widget", etc.
* @param modelWidget The widget
*/
public void renderEndingBoundaryComment(Appendable writer, String widgetType, ModelWidget modelWidget) throws IOException {
if (this.widgetCommentsEnabled) {
StringWriter sr = new StringWriter();
sr.append("<@formatBoundaryComment ");
sr.append(" boundaryType=\"");
sr.append("End");
sr.append("\" widgetType=\"");
sr.append(widgetType);
sr.append("\" widgetName=\"");
sr.append(modelWidget.getBoundaryCommentName());
sr.append("\" />");
executeMacro(writer, sr.toString());
}
}
public void renderMenuOpen(Appendable writer, Map<String, Object> context, ModelMenu modelMenu) throws IOException {
if (!userLoginIdHasChanged) {
userLoginIdHasChanged = userLoginIdHasChanged();
}
this.widgetCommentsEnabled = ModelWidget.widgetBoundaryCommentsEnabled(context);
renderBeginningBoundaryComment(writer, "Menu Widget", modelMenu);
String menuId = modelMenu.getId();
String menuContainerStyle = modelMenu.getMenuContainerStyle(context);
String menuWidth = modelMenu.getMenuWidth();
String menuTitle = modelMenu.getTitle(context);
int menuItemCount = modelMenu.renderedMenuItemCount(context);
StringWriter sr = new StringWriter();
sr.append("<@renderMenuOpen ");
sr.append(" menuId=\"");
sr.append(menuId);
sr.append("\" containerStyle=\"");
sr.append(menuContainerStyle);
sr.append("\" menuWidth=\"");
sr.append(menuWidth);
sr.append("\" menuTitle=\"");
sr.append(menuTitle);
sr.append("\" menuItemCount=\"");
sr.append(String.valueOf(menuItemCount));
sr.append("\" />");
executeMacro(writer, sr.toString());
}
/* (non-Javadoc)
* @see cn.gorun8.widget.menu.MenuStringRenderer#renderMenuClose(java.io.Writer, java.util.Map, cn.gorun8.widget.menu.ModelMenu)
*/
public void renderMenuClose(Appendable writer, Map<String, Object> context, ModelMenu modelMenu) throws IOException {
// TODO: div can't be directly inside an UL
String fillStyle = modelMenu.getFillStyle();
int menuItemCount = modelMenu.renderedMenuItemCount(context);
renderEndingBoundaryComment(writer, "Menu Widget", modelMenu);
StringWriter sr = new StringWriter();
sr.append("<@renderMenuClose ");
sr.append(" fillStyle=\"");
sr.append(fillStyle);
sr.append("\" menuItemCount=\"");
sr.append(String.valueOf(menuItemCount));
sr.append("\" />");
executeMacro(writer, sr.toString());
userLoginIdHasChanged = userLoginIdHasChanged();
GenericValue userLogin = (GenericValue)request.getSession().getAttribute("userLogin");
if (userLogin != null) {
String userLoginId = userLogin.getString("userLoginId");
//request.getSession().setAttribute("userLoginIdAtPermGrant", userLoginId);
setUserLoginIdAtPermGrant(userLoginId);
//Debug.logInfo("in HtmlMenuRenderer, userLoginId(Close):" + userLoginId + " userLoginIdAtPermGrant:" + request.getSession().getAttribute("userLoginIdAtPermGrant"),"");
} else {
request.getSession().setAttribute("userLoginIdAtPermGrant", null);
}
}
public void renderFormatSimpleWrapperOpen(Appendable writer, Map<String, Object> context, ModelMenu modelMenu) throws IOException {
//appendWhitespace(writer);
}
public void renderFormatSimpleWrapperClose(Appendable writer, Map<String, Object> context, ModelMenu modelMenu) throws IOException {
//appendWhitespace(writer);
}
/**
* @param string
*/
public void setUserLoginIdAtPermGrant(String string) {
//Debug.logInfo("in HtmlMenuRenderer, userLoginIdAtPermGrant(setUserLoginIdAtPermGrant):" + string,"");
this.userLoginIdAtPermGrant = string;
}
public String getUserLoginIdAtPermGrant() {
return this.userLoginIdAtPermGrant;
}
public boolean isHideIfSelected(ModelMenuItem menuItem, Map<String, Object> context) {
ModelMenu menu = menuItem.getModelMenu();
String currentMenuItemName = menu.getSelectedMenuItemContextFieldName(context);
String currentItemName = menuItem.getName();
Boolean hideIfSelected = menuItem.getHideIfSelected();
//Debug.logInfo("in HtmlMenuRenderer, currentMenuItemName:" + currentMenuItemName + " currentItemName:" + currentItemName + " hideIfSelected:" + hideIfSelected,"");
return (hideIfSelected != null && hideIfSelected.booleanValue() && currentMenuItemName != null && currentMenuItemName.equals(currentItemName));
}
public boolean userLoginIdHasChanged() {
boolean hasChanged = false;
GenericValue userLogin = (GenericValue)request.getSession().getAttribute("userLogin");
userLoginIdAtPermGrant = getUserLoginIdAtPermGrant();
//userLoginIdAtPermGrant = (String)request.getSession().getAttribute("userLoginIdAtPermGrant");
String userLoginId = null;
if (userLogin != null)
userLoginId = userLogin.getString("userLoginId");
//Debug.logInfo("in HtmlMenuRenderer, userLoginId:" + userLoginId + " userLoginIdAtPermGrant:" + userLoginIdAtPermGrant ,"");
if ((userLoginId == null && userLoginIdAtPermGrant != null)
|| (userLoginId != null && userLoginIdAtPermGrant == null)
|| ((userLoginId != null && userLoginIdAtPermGrant != null)
&& !userLoginId.equals(userLoginIdAtPermGrant))) {
hasChanged = true;
} else {
if (userLoginIdAtPermGrant != null)
hasChanged = true;
else
hasChanged = false;
userLoginIdAtPermGrant = null;
}
return hasChanged;
}
public void setUserLoginIdHasChanged(boolean b) {
userLoginIdHasChanged = b;
}
public String getTitle(ModelMenuItem menuItem, Map<String, Object> context) {
String title = null;
title = menuItem.getTitle(context);
return title;
}
public void renderLink(Appendable writer, Map<String, Object> context, ModelMenuItem.Link link) throws IOException {
String target = link.getTarget(context);
ModelMenuItem menuItem = link.getLinkMenuItem();
if (menuItem.getDisabled() || isDisableIfEmpty(menuItem, context)) {
target = null;
}
HttpServletResponse response = (HttpServletResponse) context.get("response");
//HttpServletRequest request = (HttpServletRequest) context.get("request");
String targetWindow = link.getTargetWindow(context);
String uniqueItemName = menuItem.getModelMenu().getName() + "_" + menuItem.getName() + "_LF_" + UtilMisc.<String>addToBigDecimalInMap(context, "menuUniqueItemIndex", BigDecimal.ONE);
String linkType = WidgetWorker.determineAutoLinkType(link.getLinkType(), target, link.getUrlMode(), request);
String id = link.getId(context);
String style = link.getStyle(context);
String name = link.getName(context);
String confirmationMsg = link.getConfirmation(context);
String text = link.getText(context);
String imgid ="";
String imgstyle ="";
String imgwid = "";
String imghgt = "";
String imgborder = "";
String imgsrc = "";
StringBuffer tmpbuf = new StringBuffer();
StringBufferWriter strWriter = new StringBufferWriter(tmpbuf);
WidgetWorker.buildHyperlinkUrl(strWriter, target, link.getUrlMode(), null, link.getPrefix(context),
link.getFullPath(), link.getSecure(), link.getEncode(), request, response, context);
String hyperlinkUrl = strWriter.toString();
Image image = link.getImage();
if (image != null) {
imgid = image.getId(context);
imgstyle = image.getStyle(context);
imgwid = image.getWidth(context);
imghgt = image.getHeight(context);
imgborder = image.getBorder(context);
imgsrc = image.getSrc(context);
imgid = UtilValidate.isNotEmpty(imgid)?imgid:"";
imgstyle = UtilValidate.isNotEmpty(imgstyle)?imgstyle:"";
imgwid = UtilValidate.isNotEmpty(imgwid)?imgwid:"";
imghgt = UtilValidate.isNotEmpty(imghgt)?imghgt:"";
imgborder = UtilValidate.isNotEmpty(imgborder)?imgborder:"";
imgsrc = UtilValidate.isNotEmpty(imgsrc)?imgsrc:"";
}
StringWriter sr = new StringWriter();
sr.append("<@renderLink ");
sr.append(" targetWindow=\"");
sr.append( targetWindow);
sr.append("\" uniqueItemName=\"");
sr.append( uniqueItemName);
sr.append("\" linkType=\"");
sr.append( linkType);
sr.append("\" id=\"");
sr.append( id);
sr.append("\" style=\"");
sr.append( style);
sr.append("\" name=\"");
sr.append( name);
sr.append("\" confirmationMsg=\"");
sr.append( confirmationMsg);
sr.append("\" imgid=\"");
sr.append( imgid);
sr.append("\" imgstyle=\"");
sr.append( imgstyle);
sr.append("\" imgwid=\"");
sr.append( imgwid);
sr.append("\" imghgt=\"");
sr.append( imghgt);
sr.append("\" imgborder=\"");
sr.append( imgborder);
sr.append("\" imgsrc=\"");
sr.append( imgsrc);
sr.append("\" text=\"");
sr.append( text);
sr.append("\" hyperlinkUrl=\"");
sr.append( hyperlinkUrl);
sr.append("\" />");
executeMacro(writer, sr.toString());
}
public void renderImage(Appendable writer, Map<String, Object> context, ModelMenuItem.Image image) throws IOException {
// open tag
writer.append("<img ");
String id = image.getId(context);
if (UtilValidate.isNotEmpty(id)) {
writer.append(" id=\"");
writer.append(id);
writer.append("\"");
}
String style = image.getStyle(context);
if (UtilValidate.isNotEmpty(style)) {
writer.append(" class=\"");
writer.append(style);
writer.append("\"");
}
String wid = image.getWidth(context);
if (UtilValidate.isNotEmpty(wid)) {
writer.append(" width=\"");
writer.append(wid);
writer.append("\"");
}
String hgt = image.getHeight(context);
if (UtilValidate.isNotEmpty(hgt)) {
writer.append(" height=\"");
writer.append(hgt);
writer.append("\"");
}
String border = image.getBorder(context);
if (UtilValidate.isNotEmpty(border)) {
writer.append(" border=\"");
writer.append(border);
writer.append("\"");
}
String src = image.getSrc(context);
if (UtilValidate.isNotEmpty(src)) {
writer.append(" src=\"");
String urlMode = image.getUrlMode();
boolean fullPath = false;
boolean secure = false;
boolean encode = false;
HttpServletResponse response = (HttpServletResponse) context.get("response");
HttpServletRequest request = (HttpServletRequest) context.get("request");
if (urlMode != null && urlMode.equalsIgnoreCase("gorun8")) {
if (request != null && response != null) {
ServletContext ctx = (ServletContext) request.getAttribute("servletContext");
RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_");
String urlString = rh.makeLink(request, response, src, fullPath, secure, encode);
writer.append(urlString);
} else {
writer.append(src);
}
} else if (urlMode != null && urlMode.equalsIgnoreCase("content")) {
if (request != null && response != null) {
StringBuilder newURL = new StringBuilder();
ContentUrlTag.appendContentPrefix(request, newURL);
newURL.append(src);
writer.append(newURL.toString());
}
} else {
writer.append(src);
}
writer.append("\"");
}
writer.append("/>");
}
}
明天我們將講如何定義FTL模板。