svn commit: r1652852 [19/22] - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/cms/ applications/content/src/org/ofbiz/content/content/ applications/content/src/org/ofbiz/content/data/ applications/content/src/org/ofbiz/content/output/ appl...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1652852 [19/22] - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/cms/ applications/content/src/org/ofbiz/content/content/ applications/content/src/org/ofbiz/content/data/ applications/content/src/org/ofbiz/content/output/ appl...

adrianc
Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/renderer/macro/MacroFormRenderer.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/renderer/macro/MacroFormRenderer.java?rev=1652852&view=auto
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/renderer/macro/MacroFormRenderer.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/renderer/macro/MacroFormRenderer.java Sun Jan 18 21:03:40 2015
@@ -0,0 +1,3132 @@
+/*******************************************************************************
+ * 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.rmi.server.UID;
+import java.sql.Timestamp;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+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.UtilFormatOut;
+import org.ofbiz.base.util.UtilGenerics;
+import org.ofbiz.base.util.UtilHttp;
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.base.util.template.FreeMarkerWorker;
+import org.ofbiz.entity.Delegator;
+import org.ofbiz.webapp.control.RequestHandler;
+import org.ofbiz.webapp.taglib.ContentUrlTag;
+import org.ofbiz.widget.WidgetWorker;
+import org.ofbiz.widget.model.CommonWidgetModels;
+import org.ofbiz.widget.model.FieldInfo;
+import org.ofbiz.widget.model.ModelForm;
+import org.ofbiz.widget.model.ModelFormField;
+import org.ofbiz.widget.model.ModelFormField.CheckField;
+import org.ofbiz.widget.model.ModelFormField.ContainerField;
+import org.ofbiz.widget.model.ModelFormField.DateFindField;
+import org.ofbiz.widget.model.ModelFormField.DateTimeField;
+import org.ofbiz.widget.model.ModelFormField.DisplayEntityField;
+import org.ofbiz.widget.model.ModelFormField.DisplayField;
+import org.ofbiz.widget.model.ModelFormField.DropDownField;
+import org.ofbiz.widget.model.ModelFormField.FieldInfoWithOptions;
+import org.ofbiz.widget.model.ModelFormField.FileField;
+import org.ofbiz.widget.model.ModelFormField.HiddenField;
+import org.ofbiz.widget.model.ModelFormField.HyperlinkField;
+import org.ofbiz.widget.model.ModelFormField.IgnoredField;
+import org.ofbiz.widget.model.ModelFormField.ImageField;
+import org.ofbiz.widget.model.ModelFormField.LookupField;
+import org.ofbiz.widget.model.ModelFormField.PasswordField;
+import org.ofbiz.widget.model.ModelFormField.RadioField;
+import org.ofbiz.widget.model.ModelFormField.RangeFindField;
+import org.ofbiz.widget.model.ModelFormField.ResetField;
+import org.ofbiz.widget.model.ModelFormField.SubmitField;
+import org.ofbiz.widget.model.ModelFormField.TextField;
+import org.ofbiz.widget.model.ModelFormField.TextFindField;
+import org.ofbiz.widget.model.ModelFormField.TextareaField;
+import org.ofbiz.widget.model.ModelFormFieldBuilder;
+import org.ofbiz.widget.model.ModelScreenWidget;
+import org.ofbiz.widget.model.ModelWidget;
+import org.ofbiz.widget.renderer.FormRenderer;
+import org.ofbiz.widget.renderer.FormStringRenderer;
+import org.ofbiz.widget.renderer.Paginator;
+import org.ofbiz.widget.renderer.UtilHelpText;
+
+import com.ibm.icu.util.Calendar;
+
+import freemarker.core.Environment;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+/**
+ * Widget Library - Form Renderer implementation based on Freemarker macros
+ *
+ */
+public final class MacroFormRenderer implements FormStringRenderer {
+
+    public static final String module = MacroFormRenderer.class.getName();
+    private final Template macroLibrary;
+    private final WeakHashMap<Appendable, Environment> environments = new WeakHashMap<Appendable, Environment>();
+    private final UtilCodec.SimpleEncoder internalEncoder;
+    private final RequestHandler rh;
+    private final HttpServletRequest request;
+    private final HttpServletResponse response;
+    private final boolean javaScriptEnabled;
+    private boolean renderPagination = true;
+    private boolean widgetCommentsEnabled = false;
+
+    public MacroFormRenderer(String macroLibraryPath, HttpServletRequest request, HttpServletResponse response) throws TemplateException, IOException {
+        macroLibrary = FreeMarkerWorker.getTemplate(macroLibraryPath);
+        this.request = request;
+        this.response = response;
+        ServletContext ctx = (ServletContext) request.getAttribute("servletContext");
+        this.rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_");
+        this.javaScriptEnabled = UtilHttp.isJavaScriptEnabled(request);
+        internalEncoder = UtilCodec.getEncoder("string");
+    }
+
+    @Deprecated
+    public MacroFormRenderer(String macroLibraryPath, Appendable writer, HttpServletRequest request, HttpServletResponse response) throws TemplateException, IOException {
+        this(macroLibraryPath, request, response);
+    }
+
+    public boolean getRenderPagination() {
+        return this.renderPagination;
+    }
+
+    public void setRenderPagination(boolean renderPagination) {
+        this.renderPagination = renderPagination;
+    }
+
+    private void executeMacro(Appendable writer, String macro) throws IOException {
+        try {
+            Environment environment = getEnvironment(writer);
+            Reader templateReader = new StringReader(macro);
+            Template template = new Template(new UID().toString(), templateReader, FreeMarkerWorker.getDefaultOfbizConfig());
+            templateReader.close();
+            environment.include(template);
+        } catch (TemplateException e) {
+            Debug.logError(e, "Error rendering screen thru ftl macro: " + macro, module);
+        } catch (IOException e) {
+            Debug.logError(e, "Error rendering screen thru ftl, macro: " + macro, module);
+        }
+    }
+
+    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 void appendWhitespace(Appendable writer) throws IOException {
+        // appending line ends for now, but this could be replaced with a simple space or something
+        writer.append("\r\n");
+        //writer.append(' ');
+    }
+
+    private String encode(String value, ModelFormField modelFormField, Map<String, Object> context) {
+        if (UtilValidate.isEmpty(value)) {
+            return value;
+        }
+        UtilCodec.SimpleEncoder encoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder");
+        if (modelFormField.getEncodeOutput() && encoder != null) {
+            value = encoder.encode(value);
+        } else {
+            value = internalEncoder.encode(value);
+        }
+        return value;
+    }
+
+    public void renderLabel(Appendable writer, Map<String, Object> context, ModelScreenWidget.Label label) throws IOException {
+        String labelText = label.getText(context);
+        if (UtilValidate.isEmpty(labelText)) {
+            // nothing to render
+            return;
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderLabel ");
+        sr.append("text=\"");
+        sr.append(labelText);
+        sr.append("\"");
+        sr.append(" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderDisplayField(Appendable writer, Map<String, Object> context, DisplayField displayField) throws IOException {
+        ModelFormField modelFormField = displayField.getModelFormField();
+        String idName = modelFormField.getCurrentContainerId(context);
+        String description = displayField.getDescription(context);
+        String type = displayField.getType();
+        String imageLocation = displayField.getImageLocation(context);
+        Integer size = Integer.valueOf("0");
+        String title = "";
+        if (UtilValidate.isNotEmpty(displayField.getSize())) {
+            try {
+                size = Integer.parseInt(displayField.getSize());
+            } catch (NumberFormatException nfe) {
+                Debug.logError(nfe, "Error reading size of a field fieldName=" + displayField.getModelFormField().getFieldName() + " FormName= " + displayField.getModelFormField().getModelForm().getName(), module);
+            }
+        }
+        ModelFormField.InPlaceEditor inPlaceEditor = displayField.getInPlaceEditor();
+        boolean ajaxEnabled = inPlaceEditor != null && this.javaScriptEnabled;
+        if (UtilValidate.isNotEmpty(description) && size > 0 && description.length() > size) {
+            title = description;
+            description = description.substring(0, size - 8) + "..." + description.substring(description.length() - 5);
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderDisplayField ");
+        sr.append("type=\"");
+        sr.append(type);
+        sr.append("\" imageLocation=\"");
+        sr.append(imageLocation);
+        sr.append("\" idName=\"");
+        sr.append(idName);
+        sr.append("\" description=\"");
+        sr.append(FreeMarkerWorker.encodeDoubleQuotes(description));
+        sr.append("\" title=\"");
+        sr.append(title);
+        sr.append("\" class=\"");
+        sr.append(modelFormField.getWidgetStyle());
+        sr.append("\" alert=\"");
+        sr.append(modelFormField.shouldBeRed(context) ? "true" : "false");
+        if (ajaxEnabled) {
+            String url = inPlaceEditor.getUrl(context);
+            String extraParameter = "{";
+            Map<String, Object> fieldMap = inPlaceEditor.getFieldMap(context);
+            if (fieldMap != null) {
+                Set<Entry<String, Object>> fieldSet = fieldMap.entrySet();
+                Iterator<Entry<String, Object>> fieldIterator = fieldSet.iterator();
+                int count = 0;
+                while (fieldIterator.hasNext()) {
+                    count++;
+                    Entry<String, Object> field = fieldIterator.next();
+                    extraParameter += field.getKey() + ":'" + (String) field.getValue() + "'";
+                    if (count < fieldSet.size()) {
+                        extraParameter += ',';
+                    }
+                }
+
+            }
+            extraParameter += "}";
+            sr.append("\" inPlaceEditorUrl=\"");
+            sr.append(url);
+            sr.append("\" inPlaceEditorParams=\"");
+            StringWriter inPlaceEditorParams = new StringWriter();
+            inPlaceEditorParams.append("{name: '");
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getParamName())) {
+                inPlaceEditorParams.append(inPlaceEditor.getParamName());
+            } else {
+                inPlaceEditorParams.append(modelFormField.getFieldName());
+            }
+            inPlaceEditorParams.append("'");
+            inPlaceEditorParams.append(", method: 'POST'");
+            inPlaceEditorParams.append(", submitdata: " + extraParameter);
+            inPlaceEditorParams.append(", type: 'textarea'");
+            inPlaceEditorParams.append(", select: 'true'");
+            inPlaceEditorParams.append(", onreset: function(){jQuery('#cc_" + idName + "').css('background-color', 'transparent');}");
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getCancelText())) {
+                inPlaceEditorParams.append(", cancel: '" + inPlaceEditor.getCancelText() + "'");
+            } else {
+                inPlaceEditorParams.append(", cancel: 'Cancel'");
+            }
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getClickToEditText())) {
+                inPlaceEditorParams.append(", tooltip: '" + inPlaceEditor.getClickToEditText() + "'");
+            }
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getFormClassName())) {
+                inPlaceEditorParams.append(", cssclass: '" + inPlaceEditor.getFormClassName() + "'");
+            } else {
+                inPlaceEditorParams.append(", cssclass: 'inplaceeditor-form'");
+            }
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getLoadingText())) {
+                inPlaceEditorParams.append(", indicator: '" + inPlaceEditor.getLoadingText() + "'");
+            }
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getOkControl())) {
+                inPlaceEditorParams.append(", submit: ");
+                if (!"false".equals(inPlaceEditor.getOkControl())) {
+                    inPlaceEditorParams.append("'");
+                }
+                inPlaceEditorParams.append(inPlaceEditor.getOkControl());
+                if (!"false".equals(inPlaceEditor.getOkControl())) {
+                    inPlaceEditorParams.append("'");
+                }
+            } else {
+                inPlaceEditorParams.append(", submit: 'OK'");
+            }
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getRows())) {
+                inPlaceEditorParams.append(", rows: '" + inPlaceEditor.getRows() + "'");
+            }
+            if (UtilValidate.isNotEmpty(inPlaceEditor.getCols())) {
+                inPlaceEditorParams.append(", cols: '" + inPlaceEditor.getCols() + "'");
+            }
+            inPlaceEditorParams.append("}");
+            sr.append(inPlaceEditorParams.toString());
+        }
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        if (displayField instanceof DisplayEntityField) {
+            makeHyperlinkString(writer, ((DisplayEntityField) displayField).getSubHyperlink(), context);
+        }
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderHyperlinkField(Appendable writer, Map<String, Object> context, HyperlinkField hyperlinkField) throws IOException {
+        this.request.setAttribute("image", hyperlinkField.getImageLocation(context));
+        ModelFormField modelFormField = hyperlinkField.getModelFormField();
+        String encodedAlternate = encode(hyperlinkField.getAlternate(context), modelFormField, context);
+        String encodedImageTitle = encode(hyperlinkField.getImageTitle(context), modelFormField, context);
+        this.request.setAttribute("alternate", encodedAlternate);
+        this.request.setAttribute("imageTitle", encodedImageTitle);
+        this.request.setAttribute("descriptionSize", hyperlinkField.getSize());
+        makeHyperlinkByType(writer, hyperlinkField.getLinkType(), modelFormField.getWidgetStyle(), hyperlinkField.getUrlMode(), hyperlinkField.getTarget(context), hyperlinkField.getParameterMap(context), hyperlinkField.getDescription(context), hyperlinkField.getTargetWindow(context),
+                hyperlinkField.getConfirmation(context), modelFormField, this.request, this.response, context);
+        this.appendTooltip(writer, context, modelFormField);
+        this.request.removeAttribute("image");
+        this.request.removeAttribute("descriptionSize");
+    }
+
+    public void renderTextField(Appendable writer, Map<String, Object> context, TextField textField) throws IOException {
+        ModelFormField modelFormField = textField.getModelFormField();
+        String name = modelFormField.getParameterName(context);
+        String className = "";
+        String alert = "false";
+        String mask = "";
+        String placeholder = textField.getPlaceholder(context);
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        String value = modelFormField.getEntry(context, textField.getDefaultValue(context));
+        String textSize = Integer.toString(textField.getSize());
+        String maxlength = "";
+        if (textField.getMaxlength() != null) {
+            maxlength = Integer.toString(textField.getMaxlength());
+        }
+        String event = modelFormField.getEvent();
+        String action = modelFormField.getAction(context);
+        String id = modelFormField.getCurrentContainerId(context);
+        String clientAutocomplete = "false";
+        //check for required field style on single forms
+        if ("single".equals(modelFormField.getModelForm().getType()) && modelFormField.getRequiredField()) {
+            String requiredStyle = modelFormField.getRequiredFieldStyle();
+            if (UtilValidate.isEmpty(requiredStyle))
+                requiredStyle = "required";
+            if (UtilValidate.isEmpty(className))
+                className = requiredStyle;
+            else
+                className = requiredStyle + " " + className;
+        }
+        List<ModelForm.UpdateArea> updateAreas = modelFormField.getOnChangeUpdateAreas();
+        boolean ajaxEnabled = updateAreas != null && this.javaScriptEnabled;
+        if (textField.getClientAutocompleteField() || ajaxEnabled) {
+            clientAutocomplete = "true";
+        }
+        if (UtilValidate.isNotEmpty(textField.getMask())) {
+            mask = textField.getMask();
+        }
+        String ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, "", context);
+        boolean disabled = textField.getDisabled();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderTextField ");
+        sr.append("name=\"");
+        sr.append(name);
+        sr.append("\" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" value=\"");
+        sr.append(value);
+        sr.append("\" textSize=\"");
+        sr.append(textSize);
+        sr.append("\" maxlength=\"");
+        sr.append(maxlength);
+        sr.append("\" id=\"");
+        sr.append(id);
+        sr.append("\" event=\"");
+        if (event != null) {
+            sr.append(event);
+        }
+        sr.append("\" action=\"");
+        if (action != null) {
+            sr.append(action);
+        }
+        sr.append("\" disabled=");
+        sr.append(Boolean.toString(disabled));
+        sr.append(" clientAutocomplete=\"");
+        sr.append(clientAutocomplete);
+        sr.append("\" ajaxUrl=\"");
+        sr.append(ajaxUrl);
+        sr.append("\" ajaxEnabled=");
+        sr.append(Boolean.toString(ajaxEnabled));
+        sr.append(" mask=\"");
+        sr.append(mask);
+        sr.append("\" placeholder=\"");
+        sr.append(placeholder);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        ModelFormField.SubHyperlink subHyperlink = textField.getSubHyperlink();
+        if (subHyperlink != null && subHyperlink.shouldUse(context)) {
+            makeHyperlinkString(writer, subHyperlink, context);
+        }
+        this.addAsterisks(writer, context, modelFormField);
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderTextareaField(Appendable writer, Map<String, Object> context, TextareaField textareaField) throws IOException {
+        ModelFormField modelFormField = textareaField.getModelFormField();
+        String name = modelFormField.getParameterName(context);
+        String cols = Integer.toString(textareaField.getCols());
+        String rows = Integer.toString(textareaField.getRows());
+        String id = modelFormField.getCurrentContainerId(context);
+        String className = "";
+        String alert = "false";
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        //check for required field style on single forms
+        if ("single".equals(modelFormField.getModelForm().getType()) && modelFormField.getRequiredField()) {
+            String requiredStyle = modelFormField.getRequiredFieldStyle();
+            if (UtilValidate.isEmpty(requiredStyle))
+                requiredStyle = "required";
+            if (UtilValidate.isEmpty(className))
+                className = requiredStyle;
+            else
+                className = requiredStyle + " " + className;
+        }
+        String visualEditorEnable = "";
+        String buttons = "";
+        if (textareaField.getVisualEditorEnable()) {
+            visualEditorEnable = "true";
+            buttons = textareaField.getVisualEditorButtons(context);
+            if (UtilValidate.isEmpty(buttons)) {
+                buttons = "maxi";
+            }
+        }
+        String readonly = "";
+        if (textareaField.isReadOnly()) {
+            readonly = "readonly";
+        }
+        Map<String, Object> userLogin = UtilGenerics.checkMap(context.get("userLogin"));
+        String language = "en";
+        if (userLogin != null) {
+            language = UtilValidate.isEmpty((String) userLogin.get("lastLocale")) ? "en" : (String) userLogin.get("lastLocale");
+        }
+        String value = modelFormField.getEntry(context, textareaField.getDefaultValue(context));
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderTextareaField ");
+        sr.append("name=\"");
+        sr.append(name);
+        sr.append("\" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" value=\"");
+        sr.append(value);
+        sr.append("\" cols=\"");
+        sr.append(cols);
+        sr.append("\" rows=\"");
+        sr.append(rows);
+        sr.append("\" id=\"");
+        sr.append(id);
+        sr.append("\" readonly=\"");
+        sr.append(readonly);
+        sr.append("\" visualEditorEnable=\"");
+        sr.append(visualEditorEnable);
+        sr.append("\" language=\"");
+        sr.append(language);
+        sr.append("\" buttons=\"");
+        sr.append(buttons);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.addAsterisks(writer, context, modelFormField);
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderDateTimeField(Appendable writer, Map<String, Object> context, DateTimeField dateTimeField) throws IOException {
+        ModelFormField modelFormField = dateTimeField.getModelFormField();
+        String paramName = modelFormField.getParameterName(context);
+        String defaultDateTimeString = dateTimeField.getDefaultDateTimeString(context);
+        String className = "";
+        String alert = "false";
+        String name = "";
+        String formattedMask = "";
+        String event = modelFormField.getEvent();
+        String action = modelFormField.getAction(context);
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        boolean useTimeDropDown = "time-dropdown".equals(dateTimeField.getInputMethod());
+        String stepString = dateTimeField.getStep();
+        int step = 1;
+        StringBuilder timeValues = new StringBuilder();
+        if (useTimeDropDown && UtilValidate.isNotEmpty(step)) {
+            try {
+                step = Integer.valueOf(stepString).intValue();
+            } catch (IllegalArgumentException e) {
+                Debug.logWarning("Inavalid value for step property for field[" + paramName + "] with input-method=\"time-dropdown\" " + " Found Value [" + stepString + "]  " + e.getMessage(), module);
+            }
+            timeValues.append("[");
+            for (int i = 0; i <= 59;) {
+                if (i != 0) {
+                    timeValues.append(", ");
+                }
+                timeValues.append(i);
+                i += step;
+            }
+            timeValues.append("]");
+        }
+        Map<String, String> uiLabelMap = UtilGenerics.checkMap(context.get("uiLabelMap"));
+        if (uiLabelMap == null) {
+            Debug.logWarning("Could not find uiLabelMap in context", module);
+        }
+        String localizedInputTitle = "", localizedIconTitle = "";
+        // whether the date field is short form, yyyy-mm-dd
+        boolean shortDateInput = ("date".equals(dateTimeField.getType()) || useTimeDropDown ? true : false);
+        if (useTimeDropDown) {
+            name = UtilHttp.makeCompositeParam(paramName, "date");
+        } else {
+            name = paramName;
+        }
+        // the default values for a timestamp
+        int size = 25;
+        int maxlength = 30;
+        if (shortDateInput) {
+            size = maxlength = 10;
+            if (uiLabelMap != null) {
+                localizedInputTitle = uiLabelMap.get("CommonFormatDate");
+            }
+        } else if ("time".equals(dateTimeField.getType())) {
+            size = maxlength = 8;
+            if (uiLabelMap != null) {
+                localizedInputTitle = uiLabelMap.get("CommonFormatTime");
+            }
+        } else {
+            if (uiLabelMap != null) {
+                localizedInputTitle = uiLabelMap.get("CommonFormatDateTime");
+            }
+        }
+        /*
+         * FIXME: Using a builder here is a hack. Replace the builder with appropriate code.
+         */
+        ModelFormFieldBuilder builder = new ModelFormFieldBuilder(modelFormField);
+        boolean memEncodeOutput = modelFormField.getEncodeOutput();
+        if (useTimeDropDown)
+            // If time-dropdown deactivate encodingOutput for found hour and minutes
+            // FIXME: Encoding should be controlled by the renderer, not by the model.
+            builder.setEncodeOutput(false);
+        // FIXME: modelFormField.getEntry ignores shortDateInput when converting Date objects to Strings.
+        if (useTimeDropDown) {
+            builder.setEncodeOutput(memEncodeOutput);
+        }
+        modelFormField = builder.build();
+        String contextValue = modelFormField.getEntry(context, dateTimeField.getDefaultValue(context));
+        String value = contextValue;
+        if (UtilValidate.isNotEmpty(value)) {
+            if (value.length() > maxlength) {
+                value = value.substring(0, maxlength);
+            }
+        }
+        String id = modelFormField.getCurrentContainerId(context);
+        ModelForm modelForm = modelFormField.getModelForm();
+        String formName = FormRenderer.getCurrentFormName(modelForm, context);
+        String timeDropdown = dateTimeField.getInputMethod();
+        String timeDropdownParamName = "";
+        String classString = "";
+        boolean isTwelveHour = false;
+        String timeHourName = "";
+        int hour2 = 0, hour1 = 0, minutes = 0;
+        String timeMinutesName = "";
+        String amSelected = "", pmSelected = "", ampmName = "";
+        String compositeType = "";
+        // search for a localized label for the icon
+        if (uiLabelMap != null) {
+            localizedIconTitle = uiLabelMap.get("CommonViewCalendar");
+        }
+        if (!"time".equals(dateTimeField.getType())) {
+            String tempParamName;
+            if (useTimeDropDown) {
+                tempParamName = UtilHttp.makeCompositeParam(paramName, "date");
+            } else {
+                tempParamName = paramName;
+            }
+            timeDropdownParamName = tempParamName;
+            defaultDateTimeString = UtilHttp.encodeBlanks(modelFormField.getEntry(context, defaultDateTimeString));
+        }
+        // if we have an input method of time-dropdown, then render two
+        // dropdowns
+        if (useTimeDropDown) {
+            className = modelFormField.getWidgetStyle();
+            classString = (className != null ? className : "");
+            isTwelveHour = "12".equals(dateTimeField.getClock());
+            // set the Calendar to the default time of the form or now()
+            Calendar cal = null;
+            try {
+                Timestamp defaultTimestamp = Timestamp.valueOf(contextValue);
+                cal = Calendar.getInstance();
+                cal.setTime(defaultTimestamp);
+            } catch (IllegalArgumentException e) {
+                Debug.logWarning("Form widget field [" + paramName + "] with input-method=\"time-dropdown\" was not able to understand the default time [" + defaultDateTimeString + "]. The parsing error was: " + e.getMessage(), module);
+            }
+            timeHourName = UtilHttp.makeCompositeParam(paramName, "hour");
+            if (cal != null) {
+                int hour = cal.get(Calendar.HOUR_OF_DAY);
+                hour2 = hour;
+                if (hour == 0) {
+                    hour = 12;
+                }
+                if (hour > 12) {
+                    hour -= 12;
+                }
+                hour1 = hour;
+                minutes = cal.get(Calendar.MINUTE);
+            }
+            timeMinutesName = UtilHttp.makeCompositeParam(paramName, "minutes");
+            compositeType = UtilHttp.makeCompositeParam(paramName, "compositeType");
+            // if 12 hour clock, write the AM/PM selector
+            if (isTwelveHour) {
+                amSelected = ((cal != null && cal.get(Calendar.AM_PM) == Calendar.AM) ? "selected" : "");
+                pmSelected = ((cal != null && cal.get(Calendar.AM_PM) == Calendar.PM) ? "selected" : "");
+                ampmName = UtilHttp.makeCompositeParam(paramName, "ampm");
+            }
+        }
+        //check for required field style on single forms
+        if ("single".equals(modelFormField.getModelForm().getType()) && modelFormField.getRequiredField()) {
+            String requiredStyle = modelFormField.getRequiredFieldStyle();
+            if (UtilValidate.isEmpty(requiredStyle))
+                requiredStyle = "required";
+            if (UtilValidate.isEmpty(className))
+                className = requiredStyle;
+            else
+                className = requiredStyle + " " + className;
+        }
+        String mask = dateTimeField.getMask();
+        if ("Y".equals(mask)) {
+            if ("date".equals(dateTimeField.getType())) {
+                formattedMask = "9999-99-99";
+            } else if ("time".equals(dateTimeField.getType())) {
+                formattedMask = "99:99:99";
+            } else if ("timestamp".equals(dateTimeField.getType())) {
+                formattedMask = "9999-99-99 99:99:99";
+            }
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderDateTimeField ");
+        sr.append("name=\"");
+        sr.append(name);
+        sr.append("\" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" value=\"");
+        sr.append(value);
+        sr.append("\" title=\"");
+        sr.append(localizedInputTitle);
+        sr.append("\" size=\"");
+        sr.append(Integer.toString(size));
+        sr.append("\" maxlength=\"");
+        sr.append(Integer.toString(maxlength));
+        sr.append("\" step=\"");
+        sr.append(Integer.toString(step));
+        sr.append("\" timeValues=\"");
+        sr.append(timeValues.toString());
+        sr.append("\" id=\"");
+        sr.append(id);
+        sr.append("\" event=\"");
+        sr.append(event);
+        sr.append("\" action=\"");
+        sr.append(action);
+        sr.append("\" dateType=\"");
+        sr.append(dateTimeField.getType());
+        sr.append("\" shortDateInput=");
+        sr.append(Boolean.toString(shortDateInput));
+        sr.append(" timeDropdownParamName=\"");
+        sr.append(timeDropdownParamName);
+        sr.append("\" defaultDateTimeString=\"");
+        sr.append(defaultDateTimeString);
+        sr.append("\" localizedIconTitle=\"");
+        sr.append(localizedIconTitle);
+        sr.append("\" timeDropdown=\"");
+        sr.append(timeDropdown);
+        sr.append("\" timeHourName=\"");
+        sr.append(timeHourName);
+        sr.append("\" classString=\"");
+        sr.append(classString);
+        sr.append("\" hour1=");
+        sr.append(Integer.toString(hour1));
+        sr.append(" hour2=");
+        sr.append(Integer.toString(hour2));
+        sr.append(" timeMinutesName=\"");
+        sr.append(timeMinutesName);
+        sr.append("\" minutes=");
+        sr.append(Integer.toString(minutes));
+        sr.append(" isTwelveHour=");
+        sr.append(Boolean.toString(isTwelveHour));
+        sr.append(" ampmName=\"");
+        sr.append(ampmName);
+        sr.append("\" amSelected=\"");
+        sr.append(amSelected);
+        sr.append("\" pmSelected=\"");
+        sr.append(pmSelected);
+        sr.append("\" compositeType=\"");
+        sr.append(compositeType);
+        sr.append("\" formName=\"");
+        sr.append(formName);
+        sr.append("\" mask=\"");
+        sr.append(formattedMask);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.addAsterisks(writer, context, modelFormField);
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderDropDownField(Appendable writer, Map<String, Object> context, DropDownField dropDownField) throws IOException {
+        ModelFormField modelFormField = dropDownField.getModelFormField();
+        ModelForm modelForm = modelFormField.getModelForm();
+        String currentValue = modelFormField.getEntry(context);
+        List<ModelFormField.OptionValue> allOptionValues = dropDownField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
+        ModelFormField.AutoComplete autoComplete = dropDownField.getAutoComplete();
+        String event = modelFormField.getEvent();
+        String action = modelFormField.getAction(context);
+        Integer textSize = Integer.valueOf(0);
+        if (UtilValidate.isNotEmpty(dropDownField.getTextSize())) {
+            try {
+                textSize = Integer.parseInt(dropDownField.getTextSize());
+            } catch (NumberFormatException nfe) {
+                Debug.logError(nfe, "Error reading size of a field fieldName=" + dropDownField.getModelFormField().getFieldName() + " FormName= " + dropDownField.getModelFormField().getModelForm().getName(), module);
+            }
+            if (textSize > 0 && UtilValidate.isNotEmpty(currentValue) && currentValue.length() > textSize) {
+                currentValue = currentValue.substring(0, textSize - 8) + "..." + currentValue.substring(currentValue.length() - 5);
+            }
+        }
+        boolean ajaxEnabled = autoComplete != null && this.javaScriptEnabled;
+        String className = "";
+        String alert = "false";
+        String name = modelFormField.getParameterName(context);
+        String id = modelFormField.getCurrentContainerId(context);
+        String multiple = dropDownField.getAllowMultiple() ? "multiple" : "";
+        String otherFieldName = "";
+        String formName = modelForm.getName();
+        String size = dropDownField.getSize();
+        String dDFCurrent = dropDownField.getCurrent();
+        String firstInList = "";
+        String explicitDescription = "";
+        String allowEmpty = "";
+        StringBuilder options = new StringBuilder();
+        StringBuilder ajaxOptions = new StringBuilder();
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        //check for required field style on single forms
+        if ("single".equals(modelFormField.getModelForm().getType()) && modelFormField.getRequiredField()) {
+            String requiredStyle = modelFormField.getRequiredFieldStyle();
+            if (UtilValidate.isEmpty(requiredStyle))
+                requiredStyle = "required";
+            if (UtilValidate.isEmpty(className))
+                className = requiredStyle;
+            else
+                className = requiredStyle + " " + className;
+        }
+        String currentDescription = null;
+        if (UtilValidate.isNotEmpty(currentValue)) {
+            for (ModelFormField.OptionValue optionValue : allOptionValues) {
+                if (optionValue.getKey().equals(currentValue)) {
+                    currentDescription = optionValue.getDescription();
+                    break;
+                }
+            }
+        }
+        int otherFieldSize = dropDownField.getOtherFieldSize();
+        if (otherFieldSize > 0) {
+            otherFieldName = dropDownField.getParameterNameOther(context);
+        }
+        // if the current value should go first, stick it in
+        if (UtilValidate.isNotEmpty(currentValue) && "first-in-list".equals(dropDownField.getCurrent())) {
+            firstInList = "first-in-list";
+        }
+        explicitDescription = (currentDescription != null ? currentDescription : dropDownField.getCurrentDescription(context));
+        if (UtilValidate.isEmpty(explicitDescription)) {
+            explicitDescription = (FieldInfoWithOptions.getDescriptionForOptionKey(currentValue, allOptionValues));
+        }
+        if (textSize > 0 && UtilValidate.isNotEmpty(explicitDescription) && explicitDescription.length() > textSize) {
+            explicitDescription = explicitDescription.substring(0, textSize - 8) + "..." + explicitDescription.substring(explicitDescription.length() - 5);
+        }
+        explicitDescription = encode(explicitDescription, modelFormField, context);
+        // if allow empty is true, add an empty option
+        if (dropDownField.getAllowEmpty()) {
+            allowEmpty = "Y";
+        }
+        List<String> currentValueList = null;
+        if (UtilValidate.isNotEmpty(currentValue) && dropDownField.getAllowMultiple()) {
+            // If currentValue is Array, it will start with [
+            if (currentValue.startsWith("[")) {
+                currentValueList = StringUtil.toList(currentValue);
+            } else {
+                currentValueList = UtilMisc.toList(currentValue);
+            }
+        }
+        options.append("[");
+        Iterator<ModelFormField.OptionValue> optionValueIter = allOptionValues.iterator();
+        int count = 0;
+        while (optionValueIter.hasNext()) {
+            ModelFormField.OptionValue optionValue = optionValueIter.next();
+            if (options.length() > 1) {
+                options.append(",");
+            }
+            options.append("{'key':'");
+            String key = encode(optionValue.getKey(), modelFormField, context);
+            options.append(key);
+            options.append("'");
+            options.append(",'description':'");
+            String description = optionValue.getDescription();
+            if (textSize > 0 && description.length() > textSize) {
+                description = description.substring(0, textSize - 8) + "..." + description.substring(description.length() - 5);
+            }
+            options.append(encode(description, modelFormField, context));
+
+            if (UtilValidate.isNotEmpty(currentValueList)) {
+                options.append("'");
+                options.append(",'selected':'");
+                if (currentValueList.contains(optionValue.getKey())) {
+                    options.append("selected");
+                } else {
+                    options.append("");
+                }
+            }
+
+            options.append("'}");
+            if (ajaxEnabled) {
+                count++;
+                ajaxOptions.append(optionValue.getKey()).append(": ");
+                ajaxOptions.append(" '").append(optionValue.getDescription()).append("'");
+                if (count != allOptionValues.size()) {
+                    ajaxOptions.append(", ");
+                }
+            }
+        }
+        options.append("]");
+        String noCurrentSelectedKey = dropDownField.getNoCurrentSelectedKey(context);
+        String otherValue = "", fieldName = "";
+        // Adapted from work by Yucca Korpela
+        // http://www.cs.tut.fi/~jkorpela/forms/combo.html
+        if (otherFieldSize > 0) {
+            fieldName = modelFormField.getParameterName(context);
+            Map<String, ? extends Object> dataMap = modelFormField.getMap(context);
+            if (dataMap == null) {
+                dataMap = context;
+            }
+            Object otherValueObj = dataMap.get(otherFieldName);
+            otherValue = (otherValueObj == null) ? "" : otherValueObj.toString();
+        }
+        String frequency = "";
+        String minChars = "";
+        String choices = "";
+        String autoSelect = "";
+        String partialSearch = "";
+        String partialChars = "";
+        String ignoreCase = "";
+        String fullSearch = "";
+        if (ajaxEnabled) {
+            frequency = autoComplete.getFrequency();
+            minChars = autoComplete.getMinChars();
+            choices = autoComplete.getChoices();
+            autoSelect = autoComplete.getAutoSelect();
+            partialSearch = autoComplete.getPartialSearch();
+            partialChars = autoComplete.getPartialChars();
+            ignoreCase = autoComplete.getIgnoreCase();
+            fullSearch = autoComplete.getFullSearch();
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderDropDownField ");
+        sr.append("name=\"");
+        sr.append(name);
+        sr.append("\" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" id=\"");
+        sr.append(id);
+        sr.append("\" multiple=\"");
+        sr.append(multiple);
+        sr.append("\" formName=\"");
+        sr.append(formName);
+        sr.append("\" otherFieldName=\"");
+        sr.append(otherFieldName);
+        sr.append("\" event=\"");
+        if (event != null) {
+            sr.append(event);
+        }
+        sr.append("\" action=\"");
+        if (action != null) {
+            sr.append(action);
+        }
+        sr.append("\" size=\"");
+        sr.append(size);
+        sr.append("\" firstInList=\"");
+        sr.append(firstInList);
+        sr.append("\" currentValue=\"");
+        sr.append(currentValue);
+        sr.append("\" explicitDescription=\"");
+        sr.append(explicitDescription);
+        sr.append("\" allowEmpty=\"");
+        sr.append(allowEmpty);
+        sr.append("\" options=");
+        sr.append(options.toString());
+        sr.append(" fieldName=\"");
+        sr.append(fieldName);
+        sr.append("\" otherFieldName=\"");
+        sr.append(otherFieldName);
+        sr.append("\" otherValue=\"");
+        sr.append(otherValue);
+        sr.append("\" otherFieldSize=");
+        sr.append(Integer.toString(otherFieldSize));
+        sr.append(" dDFCurrent=\"");
+        sr.append(dDFCurrent);
+        sr.append("\" ajaxEnabled=");
+        sr.append(Boolean.toString(ajaxEnabled));
+        sr.append(" noCurrentSelectedKey=\"");
+        sr.append(noCurrentSelectedKey);
+        sr.append("\" ajaxOptions=\"");
+        sr.append(ajaxOptions.toString());
+        sr.append("\" frequency=\"");
+        sr.append(frequency);
+        sr.append("\" minChars=\"");
+        sr.append(minChars);
+        sr.append("\" choices=\"");
+        sr.append(choices);
+        sr.append("\" autoSelect=\"");
+        sr.append(autoSelect);
+        sr.append("\" partialSearch=\"");
+        sr.append(partialSearch);
+        sr.append("\" partialChars=\"");
+        sr.append(partialChars);
+        sr.append("\" ignoreCase=\"");
+        sr.append(ignoreCase);
+        sr.append("\" fullSearch=\"");
+        sr.append(fullSearch);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        ModelFormField.SubHyperlink subHyperlink = dropDownField.getSubHyperlink();
+        if (subHyperlink != null && subHyperlink.shouldUse(context)) {
+            makeHyperlinkString(writer, subHyperlink, context);
+        }
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderCheckField(Appendable writer, Map<String, Object> context, CheckField checkField) throws IOException {
+        ModelFormField modelFormField = checkField.getModelFormField();
+        modelFormField.getModelForm();
+        String currentValue = modelFormField.getEntry(context);
+        Boolean allChecked = checkField.isAllChecked(context);
+        String id = modelFormField.getCurrentContainerId(context);
+        String className = "";
+        String alert = "false";
+        String name = modelFormField.getParameterName(context);
+        String event = modelFormField.getEvent();
+        String action = modelFormField.getAction(context);
+        StringBuilder items = new StringBuilder();
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        List<ModelFormField.OptionValue> allOptionValues = checkField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
+        items.append("[");
+        for (ModelFormField.OptionValue optionValue : allOptionValues) {
+            if (items.length() > 1) {
+                items.append(",");
+            }
+            items.append("{'value':'");
+            items.append(optionValue.getKey());
+            items.append("', 'description':'" + encode(optionValue.getDescription(), modelFormField, context));
+            items.append("'}");
+        }
+        items.append("]");
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderCheckField ");
+        sr.append("items=");
+        sr.append(items.toString());
+        sr.append(" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" id=\"");
+        sr.append(id);
+        sr.append("\" allChecked=");
+        sr.append((allChecked != null ? Boolean.toString(allChecked) : "\"\""));
+        sr.append(" currentValue=\"");
+        sr.append(currentValue);
+        sr.append("\" name=\"");
+        sr.append(name);
+        sr.append("\" event=\"");
+        if (event != null) {
+            sr.append(event);
+        }
+        sr.append("\" action=\"");
+        if (action != null) {
+            sr.append(action);
+        }
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderRadioField(Appendable writer, Map<String, Object> context, RadioField radioField) throws IOException {
+        ModelFormField modelFormField = radioField.getModelFormField();
+        modelFormField.getModelForm();
+        List<ModelFormField.OptionValue> allOptionValues = radioField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
+        String currentValue = modelFormField.getEntry(context);
+        String className = "";
+        String alert = "false";
+        String name = modelFormField.getParameterName(context);
+        String event = modelFormField.getEvent();
+        String action = modelFormField.getAction(context);
+        StringBuilder items = new StringBuilder();
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        String noCurrentSelectedKey = radioField.getNoCurrentSelectedKey(context);
+        items.append("[");
+        for (ModelFormField.OptionValue optionValue : allOptionValues) {
+            if (items.length() > 1) {
+                items.append(",");
+            }
+            items.append("{'key':'");
+            items.append(optionValue.getKey());
+            items.append("', 'description':'" + encode(optionValue.getDescription(), modelFormField, context));
+            items.append("'}");
+        }
+        items.append("]");
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderRadioField ");
+        sr.append("items=");
+        sr.append(items.toString());
+        sr.append(" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" currentValue=\"");
+        sr.append(currentValue);
+        sr.append("\" noCurrentSelectedKey=\"");
+        sr.append(noCurrentSelectedKey);
+        sr.append("\" name=\"");
+        sr.append(name);
+        sr.append("\" event=\"");
+        if (event != null) {
+            sr.append(event);
+        }
+        sr.append("\" action=\"");
+        if (action != null) {
+            sr.append(action);
+        }
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderSubmitField(Appendable writer, Map<String, Object> context, SubmitField submitField) throws IOException {
+        ModelFormField modelFormField = submitField.getModelFormField();
+        ModelForm modelForm = modelFormField.getModelForm();
+        String event = modelFormField.getEvent();
+        String action = modelFormField.getAction(context);
+        String title = modelFormField.getTitle(context);
+        String name = modelFormField.getParameterName(context);
+        String buttonType = submitField.getButtonType();
+        String formName = FormRenderer.getCurrentFormName(modelForm, context);
+        String imgSrc = submitField.getImageLocation(context);
+        String confirmation = submitField.getConfirmation(context);
+        String className = "";
+        String alert = "false";
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        String formId = FormRenderer.getCurrentContainerId(modelForm, context);
+        List<ModelForm.UpdateArea> updateAreas = modelForm.getOnSubmitUpdateAreas();
+        // This is here for backwards compatibility. Use on-event-update-area
+        // elements instead.
+        String backgroundSubmitRefreshTarget = submitField.getBackgroundSubmitRefreshTarget(context);
+        if (UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) {
+            if (updateAreas == null) {
+                updateAreas = new LinkedList<ModelForm.UpdateArea>();
+            }
+            updateAreas.add(new ModelForm.UpdateArea("submit", formId, backgroundSubmitRefreshTarget));
+        }
+        boolean ajaxEnabled = (UtilValidate.isNotEmpty(updateAreas) || UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) && this.javaScriptEnabled;
+        String ajaxUrl = "";
+        if (ajaxEnabled) {
+            ajaxUrl = createAjaxParamsFromUpdateAreas(updateAreas, "", context);
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderSubmitField ");
+        sr.append("buttonType=\"");
+        sr.append(buttonType);
+        sr.append("\" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" formName=\"");
+        sr.append(formName);
+        sr.append("\" title=\"");
+        sr.append(encode(title, modelFormField, context));
+        sr.append("\" name=\"");
+        sr.append(name);
+        sr.append("\" event=\"");
+        if (event != null) {
+            sr.append(event);
+        }
+        sr.append("\" action=\"");
+        if (action != null) {
+            sr.append(action);
+        }
+        sr.append("\" imgSrc=\"");
+        sr.append(imgSrc);
+        sr.append("\" containerId=\"");
+        if (ajaxEnabled) {
+            sr.append(formId);
+        }
+        sr.append("\" confirmation =\"");
+        sr.append(confirmation);
+        sr.append("\" ajaxUrl=\"");
+        if (ajaxEnabled) {
+            sr.append(ajaxUrl);
+        }
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderResetField(Appendable writer, Map<String, Object> context, ResetField resetField) throws IOException {
+        ModelFormField modelFormField = resetField.getModelFormField();
+        String name = modelFormField.getParameterName(context);
+        String className = "";
+        String alert = "false";
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        String title = modelFormField.getTitle(context);
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderResetField ");
+        sr.append(" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" name=\"");
+        sr.append(name);
+        sr.append("\" title=\"");
+        sr.append(title);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderHiddenField(Appendable writer, Map<String, Object> context, HiddenField hiddenField) throws IOException {
+        ModelFormField modelFormField = hiddenField.getModelFormField();
+        String value = hiddenField.getValue(context);
+        this.renderHiddenField(writer, context, modelFormField, value);
+    }
+
+    public void renderHiddenField(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, String value) throws IOException {
+        String name = modelFormField.getParameterName(context);
+        String action = modelFormField.getAction(context);
+        String event = modelFormField.getEvent();
+        String id = modelFormField.getCurrentContainerId(context);
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderHiddenField ");
+        sr.append(" name=\"");
+        sr.append(name);
+        sr.append("\" value=\"");
+        sr.append(value);
+        sr.append("\" id=\"");
+        sr.append(id);
+        sr.append("\" event=\"");
+        if (event != null) {
+            sr.append(event);
+        }
+        sr.append("\" action=\"");
+        if (action != null) {
+            sr.append(action);
+        }
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderIgnoredField(Appendable writer, Map<String, Object> context, IgnoredField ignoredField) {
+        // do nothing, it's an ignored field; could add a comment or something if we wanted to
+    }
+
+    public void renderFieldTitle(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
+        String titleText = modelFormField.getTitle(context);
+        String style = modelFormField.getTitleStyle();
+        String id = modelFormField.getCurrentContainerId(context);
+        StringBuilder sb = new StringBuilder();
+        if (UtilValidate.isNotEmpty(titleText)) {
+            if (" ".equals(titleText)) {
+                executeMacro(writer, "<@renderFormatEmptySpace />");
+            } else {
+                titleText = UtilHttp.encodeAmpersands(titleText);
+                titleText = encode(titleText, modelFormField, context);
+                if (UtilValidate.isNotEmpty(modelFormField.getHeaderLink())) {
+                    StringBuilder targetBuffer = new StringBuilder();
+                    FlexibleStringExpander target = FlexibleStringExpander.getInstance(modelFormField.getHeaderLink());
+                    String fullTarget = target.expandString(context);
+                    targetBuffer.append(fullTarget);
+                    String targetType = CommonWidgetModels.Link.DEFAULT_URL_MODE;
+                    if (UtilValidate.isNotEmpty(targetBuffer.toString()) && targetBuffer.toString().toLowerCase().startsWith("javascript:")) {
+                        targetType = "plain";
+                    }
+                    StringWriter sr = new StringWriter();
+                    makeHyperlinkString(sr, modelFormField.getHeaderLinkStyle(), targetType, targetBuffer.toString(), null, titleText, "", modelFormField, this.request, this.response, context, "");
+                    String title = sr.toString().replace("\"", "\'");
+                    sr = new StringWriter();
+                    sr.append("<@renderHyperlinkTitle ");
+                    sr.append(" name=\"");
+                    sr.append(modelFormField.getModelForm().getName());
+                    sr.append("\" title=\"");
+                    sr.append(FreeMarkerWorker.encodeDoubleQuotes(title));
+                    sr.append("\" />");
+                    executeMacro(writer, sr.toString());
+                } else if (modelFormField.isSortField()) {
+                    renderSortField(writer, context, modelFormField, titleText);
+                } else if (modelFormField.isRowSubmit()) {
+                    StringWriter sr = new StringWriter();
+                    sr.append("<@renderHyperlinkTitle ");
+                    sr.append(" name=\"");
+                    sr.append(modelFormField.getModelForm().getName());
+                    sr.append("\" title=\"");
+                    sr.append(titleText);
+                    sr.append("\" showSelectAll=\"Y\"/>");
+                    executeMacro(writer, sr.toString());
+                } else {
+                    sb.append(titleText);
+                }
+            }
+        }
+        if (!sb.toString().isEmpty()) {
+            //check for required field style on single forms
+            if ("single".equals(modelFormField.getModelForm().getType()) && modelFormField.getRequiredField()) {
+                String requiredStyle = modelFormField.getRequiredFieldStyle();
+                if (UtilValidate.isNotEmpty(requiredStyle)) {
+                    style = requiredStyle;
+                }
+            }
+            StringWriter sr = new StringWriter();
+            sr.append("<@renderFieldTitle ");
+            sr.append(" style=\"");
+            sr.append(style);
+            String displayHelpText = UtilProperties.getPropertyValue("widget.properties", "widget.form.displayhelpText");
+            if ("Y".equals(displayHelpText)) {
+                Delegator delegator = WidgetWorker.getDelegator(context);
+                Locale locale = (Locale) context.get("locale");
+                String entityName = modelFormField.getEntityName();
+                String fieldName = modelFormField.getFieldName();
+                String helpText = UtilHelpText.getEntityFieldDescription(entityName, fieldName, delegator, locale);
+
+                sr.append("\" fieldHelpText=\"");
+                sr.append(FreeMarkerWorker.encodeDoubleQuotes(helpText));
+            }
+            sr.append("\" title=\"");
+            sr.append(sb.toString());
+            if (UtilValidate.isNotEmpty(id)) {
+                sr.append("\" id=\"");
+                sr.append(id);
+                sr.append("_title");
+                // Render "for"
+                sr.append("\" for=\"");
+                sr.append(id);
+            }
+            sr.append("\" />");
+            executeMacro(writer, sr.toString());
+        }
+    }
+
+    public void renderSingleFormFieldTitle(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
+        renderFieldTitle(writer, context, modelFormField);
+    }
+
+    public void renderFormOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        this.widgetCommentsEnabled = ModelWidget.widgetBoundaryCommentsEnabled(context);
+        renderBeginningBoundaryComment(writer, "Form Widget - Form Element", modelForm);
+        String targetType = modelForm.getTargetType();
+        String targ = modelForm.getTarget(context, targetType);
+        StringBuilder linkUrl = new StringBuilder();
+        if (UtilValidate.isNotEmpty(targ)) {
+            //this.appendOfbizUrl(writer, "/" + targ);
+            WidgetWorker.buildHyperlinkUrl(linkUrl, targ, targetType, null, null, false, false, true, request, response, context);
+        }
+        String formType = modelForm.getType();
+        String targetWindow = modelForm.getTargetWindow(context);
+        String containerId = FormRenderer.getCurrentContainerId(modelForm, context);
+        String containerStyle = modelForm.getContainerStyle();
+        String autocomplete = "";
+        String name = FormRenderer.getCurrentFormName(modelForm, context);
+        String viewIndexField = modelForm.getMultiPaginateIndexField(context);
+        String viewSizeField = modelForm.getMultiPaginateSizeField(context);
+        int viewIndex = Paginator.getViewIndex(modelForm, context);
+        int viewSize = Paginator.getViewSize(modelForm, context);
+        boolean useRowSubmit = modelForm.getUseRowSubmit();
+        if (!modelForm.getClientAutocompleteFields()) {
+            autocomplete = "off";
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormOpen ");
+        sr.append(" linkUrl=\"");
+        sr.append(linkUrl);
+        sr.append("\" formType=\"");
+        sr.append(formType);
+        sr.append("\" targetWindow=\"");
+        sr.append(targetWindow);
+        sr.append("\" containerId=\"");
+        sr.append(containerId);
+        sr.append("\" containerStyle=\"");
+        sr.append(containerStyle);
+        sr.append("\" autocomplete=\"");
+        sr.append(autocomplete);
+        sr.append("\" name=\"");
+        sr.append(name);
+        sr.append("\" viewIndexField=\"");
+        sr.append(viewIndexField);
+        sr.append("\" viewSizeField=\"");
+        sr.append(viewSizeField);
+        sr.append("\" viewIndex=\"");
+        sr.append(Integer.toString(viewIndex));
+        sr.append("\" viewSize=\"");
+        sr.append(Integer.toString(viewSize));
+        sr.append("\" useRowSubmit=");
+        sr.append(Boolean.toString(useRowSubmit));
+        sr.append(" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        String focusFieldName = FormRenderer.getFocusFieldName(modelForm, context);
+        String formName = FormRenderer.getCurrentFormName(modelForm, context);
+        String containerId = FormRenderer.getCurrentContainerId(modelForm, context);
+        String hasRequiredField = "";
+        for (ModelFormField formField : modelForm.getFieldList()) {
+            if (formField.getRequiredField()) {
+                hasRequiredField = "Y";
+                break;
+            }
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormClose ");
+        sr.append(" focusFieldName=\"");
+        sr.append(focusFieldName);
+        sr.append("\" formName=\"");
+        sr.append(formName);
+        sr.append("\" containerId=\"");
+        sr.append(containerId);
+        sr.append("\" hasRequiredField=\"");
+        sr.append(hasRequiredField);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        renderEndingBoundaryComment(writer, "Form Widget - Form Element", modelForm);
+    }
+
+    public void renderMultiFormClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        //FIXME copy from HtmlFormRenderer.java (except for the closing form tag itself, that is now converted)
+        Iterator<ModelFormField> submitFields = modelForm.getMultiSubmitFields().iterator();
+        while (submitFields.hasNext()) {
+            ModelFormField submitField = submitFields.next();
+            if (submitField != null && submitField.shouldUse(context)) {
+                // Threw this in that as a hack to keep the submit button from expanding the first field
+                // Needs a more rugged solution
+                // WARNING: this method (renderMultiFormClose) must be called after the
+                // table that contains the list has been closed (to avoid validation errors) so
+                // we cannot call here the methods renderFormatItemRowCell*: for this reason
+                // they are now commented.
+                // this.renderFormatItemRowCellOpen(writer, context, modelForm, submitField);
+                // this.renderFormatItemRowCellClose(writer, context, modelForm, submitField);
+                // this.renderFormatItemRowCellOpen(writer, context, modelForm, submitField);
+                submitField.renderFieldString(writer, context, this);
+                // this.renderFormatItemRowCellClose(writer, context, modelForm, submitField);
+            }
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderMultiFormClose />");
+        executeMacro(writer, sr.toString());
+        // see if there is anything that needs to be added outside of the multi-form
+        Map<String, Object> wholeFormContext = UtilGenerics.checkMap(context.get("wholeFormContext"));
+        Appendable postMultiFormWriter = wholeFormContext != null ? (Appendable) wholeFormContext.get("postMultiFormWriter") : null;
+        if (postMultiFormWriter != null) {
+            writer.append(postMultiFormWriter.toString());
+            appendWhitespace(writer);
+        }
+        renderEndingBoundaryComment(writer, "Form Widget - Form Element (Multi)", modelForm);
+    }
+
+    public void renderFormatListWrapperOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        Map<String, Object> inputFields = UtilGenerics.checkMap(context.get("requestParameters"));
+        Map<String, Object> queryStringMap = UtilGenerics.toMap(context.get("queryStringMap"));
+        if (UtilValidate.isNotEmpty(queryStringMap)) {
+            inputFields.putAll(queryStringMap);
+        }
+        if (modelForm.getType().equals("multi")) {
+            inputFields = UtilHttp.removeMultiFormParameters(inputFields);
+        }
+        String queryString = UtilHttp.urlEncodeArgs(inputFields);
+        context.put("_QBESTRING_", queryString);
+        renderBeginningBoundaryComment(writer, "Form Widget", modelForm);
+        if (this.renderPagination) {
+            this.renderNextPrev(writer, context, modelForm);
+        }
+        List<ModelFormField> childFieldList = modelForm.getFieldList();
+        List<String> columnStyleList = new LinkedList<String>();
+        List<String> fieldNameList = new LinkedList<String>();
+        for (ModelFormField childField : childFieldList) {
+            int childFieldType = childField.getFieldInfo().getFieldType();
+            if (childFieldType == FieldInfo.HIDDEN || childFieldType == FieldInfo.IGNORED) {
+                continue;
+            }
+            String areaStyle = childField.getTitleAreaStyle();
+            if (UtilValidate.isEmpty(areaStyle)) {
+                areaStyle = "";
+            }
+            if (fieldNameList.contains(childField.getName())) {
+                if (UtilValidate.isNotEmpty(areaStyle)) {
+                    columnStyleList.set(fieldNameList.indexOf(childField.getName()), areaStyle);
+                }
+            } else {
+                columnStyleList.add(areaStyle);
+                fieldNameList.add(childField.getName());
+            }
+        }
+        columnStyleList = StringUtil.quoteStrList(columnStyleList);
+        String columnStyleListString = StringUtil.join(columnStyleList, ", ");
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatListWrapperOpen ");
+        sr.append(" formName=\"");
+        sr.append(modelForm.getName());
+        sr.append("\" style=\"");
+        sr.append(FlexibleStringExpander.expandString(modelForm.getDefaultTableStyle(), context));
+        sr.append("\" columnStyles=[");
+        if (UtilValidate.isNotEmpty(columnStyleListString)) {
+            // this is a fix for forms with no fields
+            sr.append(columnStyleListString);
+        }
+        sr.append("] />");
+        executeMacro(writer, sr.toString());
+
+    }
+
+    public void renderFormatListWrapperClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatListWrapperClose");
+        sr.append(" formName=\"");
+        sr.append(modelForm.getName());
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        if (this.renderPagination) {
+            this.renderNextPrev(writer, context, modelForm);
+        }
+        renderEndingBoundaryComment(writer, "Form Widget - Formal List Wrapper", modelForm);
+    }
+
+    public void renderFormatHeaderRowOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        String headerStyle = FlexibleStringExpander.expandString(modelForm.getHeaderRowStyle(), context);
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowOpen ");
+        sr.append(" style=\"");
+        sr.append(headerStyle);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatHeaderRowClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatHeaderRowCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField, int positionSpan) throws IOException {
+        String areaStyle = modelFormField.getTitleAreaStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowCellOpen ");
+        sr.append(" style=\"");
+        sr.append(areaStyle);
+        sr.append("\" positionSpan=");
+        sr.append(Integer.toString(positionSpan));
+        sr.append(" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatHeaderRowCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowCellClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatHeaderRowFormCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        String areaStyle = modelForm.getFormTitleAreaStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowFormCellOpen ");
+        sr.append(" style=\"");
+        sr.append(areaStyle);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatHeaderRowFormCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowFormCellClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatHeaderRowFormCellTitleSeparator(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField, boolean isLast) throws IOException {
+        String titleStyle = modelFormField.getTitleStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatHeaderRowFormCellTitleSeparator ");
+        sr.append(" style=\"");
+        sr.append(titleStyle);
+        sr.append("\" isLast=");
+        sr.append(Boolean.toString(isLast));
+        sr.append(" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatItemRowOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        Integer itemIndex = (Integer) context.get("itemIndex");
+        String altRowStyles = "";
+        String evenRowStyle = "";
+        String oddRowStyle = "";
+        if (itemIndex != null) {
+            altRowStyles = modelForm.getStyleAltRowStyle(context);
+            if (itemIndex.intValue() % 2 == 0) {
+                evenRowStyle = modelForm.getEvenRowStyle();
+            } else {
+                oddRowStyle = FlexibleStringExpander.expandString(modelForm.getOddRowStyle(), context);
+            }
+        }
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatItemRowOpen ");
+        sr.append(" formName=\"");
+        sr.append(modelForm.getName());
+        sr.append("\" itemIndex=");
+        sr.append(Integer.toString(itemIndex));
+        sr.append(" altRowStyles=\"");
+        sr.append(altRowStyles);
+        sr.append("\" evenRowStyle=\"");
+        sr.append(evenRowStyle);
+        sr.append("\" oddRowStyle=\"");
+        sr.append(oddRowStyle);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatItemRowClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatItemRowClose ");
+        sr.append(" formName=\"");
+        sr.append(modelForm.getName());
+        sr.append("\"/>");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatItemRowCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField, int positionSpan) throws IOException {
+        String areaStyle = modelFormField.getWidgetAreaStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatItemRowCellOpen ");
+        sr.append(" fieldName=\"");
+        sr.append(modelFormField.getName());
+        sr.append("\" style=\"");
+        sr.append(areaStyle);
+        sr.append("\" positionSpan=");
+        sr.append(Integer.toString(positionSpan));
+        sr.append(" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatItemRowCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatItemRowCellClose");
+        sr.append(" fieldName=\"");
+        sr.append(modelFormField.getName());
+        sr.append("\"/>");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatItemRowFormCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        String areaStyle = modelForm.getFormTitleAreaStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatItemRowFormCellOpen ");
+        sr.append(" style=\"");
+        sr.append(areaStyle);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatItemRowFormCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatItemRowFormCellClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatSingleWrapperOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        String style = FlexibleStringExpander.expandString(modelForm.getDefaultTableStyle(), context);
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatSingleWrapperOpen ");
+        sr.append(" formName=\"");
+        sr.append(modelForm.getName());
+        sr.append("\" style=\"");
+        sr.append(style);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatSingleWrapperClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatSingleWrapperClose");
+        sr.append(" formName=\"");
+        sr.append(modelForm.getName());
+        sr.append("\"/>");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatFieldRowOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatFieldRowOpen />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatFieldRowClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatFieldRowClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatFieldRowTitleCellOpen(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
+        String style = modelFormField.getTitleAreaStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatFieldRowTitleCellOpen ");
+        sr.append(" style=\"");
+        sr.append(style);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatFieldRowTitleCellClose(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatFieldRowTitleCellClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatFieldRowSpacerCell(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
+    }
+
+    public void renderFormatFieldRowWidgetCellOpen(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, int positions, int positionSpan, Integer nextPositionInRow) throws IOException {
+        String areaStyle = modelFormField.getWidgetAreaStyle();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatFieldRowWidgetCellOpen ");
+        sr.append(" positionSpan=");
+        sr.append(Integer.toString(positionSpan));
+        sr.append(" style=\"");
+        sr.append(areaStyle);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatFieldRowWidgetCellClose(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, int positions, int positionSpan, Integer nextPositionInRow) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatFieldRowWidgetCellClose />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderFormatEmptySpace(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderFormatEmptySpace />");
+        executeMacro(writer, sr.toString());
+    }
+
+    public void renderTextFindField(Appendable writer, Map<String, Object> context, TextFindField textFindField) throws IOException {
+        ModelFormField modelFormField = textFindField.getModelFormField();
+        String defaultOption = textFindField.getDefaultOption();
+        String className = "";
+        String alert = "false";
+        String opEquals = "";
+        String opBeginsWith = "";
+        String opContains = "";
+        String opIsEmpty = "";
+        String opNotEqual = "";
+        String name = modelFormField.getParameterName(context);
+        String size = Integer.toString(textFindField.getSize());
+        String maxlength = "";
+        String autocomplete = "";
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        Locale locale = (Locale) context.get("locale");
+        if (!textFindField.getHideOptions()) {
+            opEquals = UtilProperties.getMessage("conditional", "equals", locale);
+            opBeginsWith = UtilProperties.getMessage("conditional", "begins_with", locale);
+            opContains = UtilProperties.getMessage("conditional", "contains", locale);
+            opIsEmpty = UtilProperties.getMessage("conditional", "is_empty", locale);
+            opNotEqual = UtilProperties.getMessage("conditional", "not_equal", locale);
+        }
+        String value = modelFormField.getEntry(context, textFindField.getDefaultValue(context));
+        if (value == null) {
+            value = "";
+        }
+        if (textFindField.getMaxlength() != null) {
+            maxlength = textFindField.getMaxlength().toString();
+        }
+        if (!textFindField.getClientAutocompleteField()) {
+            autocomplete = "off";
+        }
+        String titleStyle = "";
+        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
+            titleStyle = modelFormField.getTitleStyle();
+        }
+        String ignoreCase = UtilProperties.getMessage("conditional", "ignore_case", locale);
+        boolean ignCase = textFindField.getIgnoreCase();
+        boolean hideIgnoreCase = textFindField.getHideIgnoreCase();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderTextFindField ");
+        sr.append(" name=\"");
+        sr.append(name);
+        sr.append("\" value=\"");
+        sr.append(value);
+        sr.append("\" defaultOption=\"");
+        sr.append(defaultOption);
+        sr.append("\" opEquals=\"");
+        sr.append(opEquals);
+        sr.append("\" opBeginsWith=\"");
+        sr.append(opBeginsWith);
+        sr.append("\" opContains=\"");
+        sr.append(opContains);
+        sr.append("\" opIsEmpty=\"");
+        sr.append(opIsEmpty);
+        sr.append("\" opNotEqual=\"");
+        sr.append(opNotEqual);
+        sr.append("\" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" size=\"");
+        sr.append(size);
+        sr.append("\" maxlength=\"");
+        sr.append(maxlength);
+        sr.append("\" autocomplete=\"");
+        sr.append(autocomplete);
+        sr.append("\" titleStyle=\"");
+        sr.append(titleStyle);
+        sr.append("\" hideIgnoreCase=");
+        sr.append(Boolean.toString(hideIgnoreCase));
+        sr.append(" ignCase=");
+        sr.append(Boolean.toString(ignCase));
+        sr.append(" ignoreCase=\"");
+        sr.append(ignoreCase);
+        sr.append("\" />");
+        executeMacro(writer, sr.toString());
+        this.appendTooltip(writer, context, modelFormField);
+    }
+
+    public void renderRangeFindField(Appendable writer, Map<String, Object> context, RangeFindField rangeFindField) throws IOException {
+        ModelFormField modelFormField = rangeFindField.getModelFormField();
+        Locale locale = (Locale) context.get("locale");
+        String opEquals = UtilProperties.getMessage("conditional", "equals", locale);
+        String opGreaterThan = UtilProperties.getMessage("conditional", "greater_than", locale);
+        String opGreaterThanEquals = UtilProperties.getMessage("conditional", "greater_than_equals", locale);
+        String opLessThan = UtilProperties.getMessage("conditional", "less_than", locale);
+        String opLessThanEquals = UtilProperties.getMessage("conditional", "less_than_equals", locale);
+        //String opIsEmpty = UtilProperties.getMessage("conditional", "is_empty", locale);
+        String className = "";
+        String alert = "false";
+        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle())) {
+            className = modelFormField.getWidgetStyle();
+            if (modelFormField.shouldBeRed(context)) {
+                alert = "true";
+            }
+        }
+        String name = modelFormField.getParameterName(context);
+        String size = Integer.toString(rangeFindField.getSize());
+        String value = modelFormField.getEntry(context, rangeFindField.getDefaultValue(context));
+        if (value == null) {
+            value = "";
+        }
+        Integer maxlength = rangeFindField.getMaxlength();
+        String autocomplete = "";
+
+        if (!rangeFindField.getClientAutocompleteField()) {
+            autocomplete = "off";
+        }
+        String titleStyle = modelFormField.getTitleStyle();
+
+        if (titleStyle == null) {
+            titleStyle = "";
+        }
+        String defaultOptionFrom = rangeFindField.getDefaultOptionFrom();
+        String value2 = modelFormField.getEntry(context);
+        if (value2 == null) {
+            value2 = "";
+        }
+        String defaultOptionThru = rangeFindField.getDefaultOptionThru();
+        StringWriter sr = new StringWriter();
+        sr.append("<@renderRangeFindField ");
+        sr.append(" className=\"");
+        sr.append(className);
+        sr.append("\" alert=\"");
+        sr.append(alert);
+        sr.append("\" name=\"");
+        sr.append(name);
+        sr.append("\" value=\"");
+        sr.append(value);
+        sr.append("\" size=\"");
+        sr.append(size);
+        sr.append("\" maxlength=\"");
+        if (maxlength != null) {
+            sr.append(Integer.toString(maxlength));
+        }
+        sr.append("\" autocomplete=\"");
+        sr.append(autocomplete);
+        sr.append("\" titleStyle=\"");
+        sr.append(titleStyle);
+        sr.append("\" defaultOptionFrom=\"");
+        sr.append(defaultOptionFrom);
+        sr.append("\" opEquals=\"");
+        sr.append(opEquals);
+        sr.append("\" opGreaterThan=\"");
+        sr.append(opGreaterThan);
+        sr.append("\" opGreaterThanEquals=\"");
+        sr.append(opGreaterThanEquals);

[... 1282 lines stripped ...]