/******************************************************************************* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*******************************************************************************/ | |
package org.ofbiz.widget.renderer.macro; | |
import java.io.IOException; | |
import java.io.Reader; | |
import java.io.StringReader; | |
import java.io.StringWriter; | |
import java.math.BigDecimal; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import javax.servlet.ServletContext; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.ofbiz.base.util.Debug; | |
import org.ofbiz.base.util.StringUtil; | |
import org.ofbiz.base.util.UtilCodec; | |
import org.ofbiz.base.util.UtilMisc; | |
import org.ofbiz.base.util.UtilValidate; | |
import org.ofbiz.base.util.template.FreeMarkerWorker; | |
import org.ofbiz.webapp.control.RequestHandler; | |
import org.ofbiz.webapp.taglib.ContentUrlTag; | |
import org.ofbiz.widget.WidgetWorker; | |
import org.ofbiz.widget.model.CommonWidgetModels.Image; | |
import org.ofbiz.widget.model.ModelMenu; | |
import org.ofbiz.widget.model.ModelMenuItem; | |
import org.ofbiz.widget.model.ModelMenuItem.MenuLink; | |
import org.ofbiz.widget.model.ModelWidget; | |
import org.ofbiz.widget.renderer.MenuStringRenderer; | |
import freemarker.core.Environment; | |
import freemarker.template.Template; | |
import freemarker.template.TemplateException; | |
public class MacroMenuRenderer implements MenuStringRenderer { | |
public static final String module = MacroMenuRenderer.class.getName(); | |
private int macroCount = 999; | |
private final Map<Appendable, Environment> environments = new HashMap<Appendable, Environment>(); | |
private final Template macroLibrary; | |
private final HttpServletRequest request; | |
private final HttpServletResponse response; | |
public MacroMenuRenderer(String macroLibraryPath, HttpServletRequest request, HttpServletResponse response) throws TemplateException, IOException { | |
this.macroLibrary = FreeMarkerWorker.getTemplate(macroLibraryPath); | |
this.request = request; | |
this.response = response; | |
} | |
// Made this a separate method so it can be externalized and reused. | |
private Map<String, Object> createImageParameters(Map<String, Object> context, Image image) { | |
Map<String, Object> parameters = new HashMap<String, Object>(); | |
parameters.put("id", image.getId(context)); | |
parameters.put("style", image.getStyle(context)); | |
parameters.put("width", image.getWidth(context)); | |
parameters.put("height", image.getHeight(context)); | |
parameters.put("border", image.getBorder(context)); | |
String src = image.getSrc(context); | |
if (UtilValidate.isNotEmpty(src) && request != null && response != null) { | |
String urlMode = image.getUrlMode(); | |
if ("ofbiz".equalsIgnoreCase(urlMode)) { | |
boolean fullPath = false; | |
boolean secure = false; | |
boolean encode = false; | |
ServletContext ctx = (ServletContext) request.getAttribute("servletContext"); | |
RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_"); | |
src = rh.makeLink(request, response, src, fullPath, secure, encode); | |
} else if ("content".equalsIgnoreCase(urlMode)) { | |
StringBuilder newURL = new StringBuilder(); | |
ContentUrlTag.appendContentPrefix(request, newURL); | |
newURL.append(src); | |
src = newURL.toString(); | |
} | |
} | |
parameters.put("src", src); | |
return parameters; | |
} | |
private void executeMacro(Appendable writer, String macro) throws IOException, TemplateException { | |
Environment environment = getEnvironment(writer); | |
Reader templateReader = new StringReader(macro); | |
macroCount++; | |
String templateName = toString().concat("_") + macroCount; | |
Template template = new Template(templateName, templateReader, FreeMarkerWorker.getDefaultOfbizConfig()); | |
templateReader.close(); | |
environment.include(template); | |
} | |
private void executeMacro(Appendable writer, String macroName, Map<String, Object> macroParameters) throws IOException, TemplateException { | |
StringBuilder sb = new StringBuilder("<@"); | |
sb.append(macroName); | |
if (macroParameters != null) { | |
for (Map.Entry<String, Object> parameter : macroParameters.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(" />"); | |
if (Debug.verboseOn()) { | |
Debug.logVerbose("Executing macro: " + sb, module); | |
} | |
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; | |
} | |
private 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; | |
} | |
private 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(); | |
return (hideIfSelected != null && hideIfSelected.booleanValue() && currentMenuItemName != null && currentMenuItemName.equals(currentItemName)); | |
} | |
@Override | |
public void renderFormatSimpleWrapperClose(Appendable writer, Map<String, Object> context, ModelMenu menu) throws IOException { | |
// Nothing to do. | |
} | |
@Override | |
public void renderFormatSimpleWrapperOpen(Appendable writer, Map<String, Object> context, ModelMenu menu) throws IOException { | |
// Nothing to do. | |
} | |
@Override | |
public void renderFormatSimpleWrapperRows(Appendable writer, Map<String, Object> context, Object menu) throws IOException { | |
List<ModelMenuItem> menuItemList = ((ModelMenu) menu).getMenuItemList(); | |
for (ModelMenuItem currentMenuItem : menuItemList) { | |
renderMenuItem(writer, context, currentMenuItem); | |
} | |
} | |
@Override | |
public void renderImage(Appendable writer, Map<String, Object> context, Image image) throws IOException { | |
Map<String, Object> parameters = createImageParameters(context, image); | |
try { | |
executeMacro(writer, "renderImage", parameters); | |
} catch (TemplateException e) { | |
throw new IOException(e); | |
} | |
} | |
@Override | |
public void renderLink(Appendable writer, Map<String, Object> context, MenuLink link) throws IOException { | |
Map<String, Object> parameters = new HashMap<String, Object>(); | |
String target = link.getTarget(context); | |
ModelMenuItem menuItem = link.getLinkMenuItem(); | |
if (isDisableIfEmpty(menuItem, context)) { | |
target = null; | |
} | |
parameters.put("id", link.getId(context)); | |
parameters.put("style", link.getStyle(context)); | |
parameters.put("name", link.getName(context)); | |
parameters.put("text", link.getText(context)); | |
parameters.put("targetWindow", link.getTargetWindow(context)); | |
String uniqueItemName = menuItem.getModelMenu().getName() + "_" + menuItem.getName() + "_LF_" + UtilMisc.<String> addToBigDecimalInMap(context, "menuUniqueItemIndex", BigDecimal.ONE); | |
if(menuItem.getModelMenu().getExtraIndex(context) != null){ | |
uniqueItemName += "_" + menuItem.getModelMenu().getExtraIndex(context); | |
} | |
parameters.put("uniqueItemName", uniqueItemName); | |
String linkType = ""; | |
if (UtilValidate.isNotEmpty(target)) { | |
linkType = WidgetWorker.determineAutoLinkType(link.getLinkType(), target, link.getUrlMode(), request); | |
} | |
parameters.put("linkType", linkType); | |
String linkUrl = ""; | |
String actionUrl = ""; | |
StringBuilder targetParameters = new StringBuilder(); | |
if ("hidden-form".equals(linkType) || "ajax-window".equals(linkType)) { | |
StringBuilder sb = new StringBuilder(); | |
WidgetWorker.buildHyperlinkUrl(sb, target, link.getUrlMode(), null, link.getPrefix(context), link.getFullPath(), link.getSecure(), link.getEncode(), request, response, context); | |
actionUrl = sb.toString(); | |
targetParameters.append("["); | |
for (Map.Entry<String, String> parameter : link.getParameterMap(context).entrySet()) { | |
if (targetParameters.length() > 1) { | |
targetParameters.append(","); | |
} | |
targetParameters.append("{'name':'"); | |
targetParameters.append(parameter.getKey()); | |
targetParameters.append("'"); | |
targetParameters.append(",'value':'"); | |
targetParameters.append(parameter.getValue()); | |
targetParameters.append("'}"); | |
} | |
targetParameters.append("]"); | |
} | |
if (targetParameters.length() == 0) { | |
targetParameters.append("\"\""); | |
} | |
if (UtilValidate.isNotEmpty(target)) { | |
if (!"hidden-form".equals(linkType)) { | |
StringBuilder sb = new StringBuilder(); | |
WidgetWorker.buildHyperlinkUrl(sb, target, link.getUrlMode(), link.getParameterMap(context), link.getPrefix(context), link.getFullPath(), link.getSecure(), link.getEncode(), request, response, context); | |
linkUrl = sb.toString(); | |
} | |
} | |
parameters.put("linkUrl", linkUrl); | |
parameters.put("actionUrl", actionUrl); | |
parameters.put("parameterList", targetParameters); | |
String imgStr = ""; | |
Image img = link.getImage(); | |
if (img != null) { | |
StringWriter sw = new StringWriter(); | |
renderImage(sw, context, img); | |
imgStr = sw.toString(); | |
} | |
parameters.put("imgStr", imgStr); | |
try { | |
executeMacro(writer, "renderLink", parameters); | |
} catch (TemplateException e) { | |
throw new IOException(e); | |
} | |
} | |
@Override | |
public void renderMenuClose(Appendable writer, Map<String, Object> context, ModelMenu menu) throws IOException { | |
Map<String, Object> parameters = null; | |
if (ModelWidget.widgetBoundaryCommentsEnabled(context)) { | |
parameters = new HashMap<String, Object>(); | |
StringBuilder sb = new StringBuilder("End Menu Widget "); | |
sb.append(menu.getBoundaryCommentName()); | |
parameters.put("boundaryComment", sb.toString()); | |
} | |
try { | |
executeMacro(writer, "renderMenuEnd", parameters); | |
} catch (TemplateException e) { | |
throw new IOException(e); | |
} | |
} | |
@Override | |
public void renderMenuItem(Appendable writer, Map<String, Object> context, ModelMenuItem menuItem) throws IOException { | |
if (isHideIfSelected(menuItem, context)) | |
return; | |
Map<String, Object> parameters = new HashMap<String, Object>(); | |
String style = menuItem.getWidgetStyle(); | |
if (menuItem.isSelected(context)) { | |
style = menuItem.getSelectedStyle(); | |
if (UtilValidate.isEmpty(style)) { | |
style = "selected"; | |
} | |
} | |
if (this.isDisableIfEmpty(menuItem, context)) { | |
style = menuItem.getDisabledTitleStyle(); | |
} | |
if (style == null) { | |
style = ""; | |
} | |
String alignStyle = menuItem.getAlignStyle(); | |
if (UtilValidate.isNotEmpty(alignStyle)) { | |
style = style.concat(" ").concat(alignStyle); | |
} | |
parameters.put("style", style); | |
parameters.put("toolTip", menuItem.getTooltip(context)); | |
String linkStr = ""; | |
MenuLink link = menuItem.getLink(); | |
if (link != null) { | |
StringWriter sw = new StringWriter(); | |
renderLink(sw, context, link); | |
linkStr = sw.toString(); | |
} else { | |
linkStr = menuItem.getTitle(context); | |
UtilCodec.SimpleEncoder simpleEncoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder"); | |
if (simpleEncoder != null) { | |
linkStr = simpleEncoder.encode(linkStr); | |
} | |
} | |
parameters.put("linkStr", linkStr); | |
boolean containsNestedMenus = !menuItem.getMenuItemList().isEmpty(); | |
parameters.put("containsNestedMenus", containsNestedMenus); | |
try { | |
executeMacro(writer, "renderMenuItemBegin", parameters); | |
} catch (TemplateException e) { | |
throw new IOException(e); | |
} | |
if (containsNestedMenus) { | |
for (ModelMenuItem childMenuItem : menuItem.getMenuItemList()) { | |
childMenuItem.renderMenuItemString(writer, context, this); | |
} | |
} | |
parameters.clear(); | |
parameters.put("containsNestedMenus", containsNestedMenus); | |
try { | |
executeMacro(writer, "renderMenuItemEnd", parameters); | |
} catch (TemplateException e) { | |
throw new IOException(e); | |
} | |
} | |
@Override | |
public void renderMenuOpen(Appendable writer, Map<String, Object> context, ModelMenu menu) throws IOException { | |
Map<String, Object> parameters = new HashMap<String, Object>(); | |
if (ModelWidget.widgetBoundaryCommentsEnabled(context)) { | |
StringBuilder sb = new StringBuilder("Begin Menu Widget "); | |
sb.append(menu.getBoundaryCommentName()); | |
parameters.put("boundaryComment", sb.toString()); | |
} | |
parameters.put("id", menu.getId()); | |
parameters.put("style", menu.getMenuContainerStyle(context)); | |
parameters.put("title", menu.getTitle(context)); | |
try { | |
executeMacro(writer, "renderMenuBegin", parameters); | |
} catch (TemplateException e) { | |
throw new IOException(e); | |
} | |
} | |
} |