blob: bcac580392735ff2f4603ea745b4713f8288283b [file] [log] [blame]
/*******************************************************************************
* 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);
}
}
}