Package org.ofbiz.widget.html

Source Code of org.ofbiz.widget.html.HtmlFormRenderer

/*******************************************************************************
* 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.html;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javolution.util.FastList;

import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.StringUtil;
import org.ofbiz.base.util.StringUtil.SimpleEncoder;
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.webapp.control.RequestHandler;
import org.ofbiz.webapp.taglib.ContentUrlTag;
import org.ofbiz.widget.ModelWidget;
import org.ofbiz.widget.WidgetWorker;
import org.ofbiz.widget.form.FormStringRenderer;
import org.ofbiz.widget.form.MacroFormRenderer;
import org.ofbiz.widget.form.ModelForm;
import org.ofbiz.widget.form.ModelFormField;
import org.ofbiz.widget.form.ModelFormField.CheckField;
import org.ofbiz.widget.form.ModelFormField.ContainerField;
import org.ofbiz.widget.form.ModelFormField.DateFindField;
import org.ofbiz.widget.form.ModelFormField.DateTimeField;
import org.ofbiz.widget.form.ModelFormField.DisplayEntityField;
import org.ofbiz.widget.form.ModelFormField.DisplayField;
import org.ofbiz.widget.form.ModelFormField.DropDownField;
import org.ofbiz.widget.form.ModelFormField.FileField;
import org.ofbiz.widget.form.ModelFormField.HiddenField;
import org.ofbiz.widget.form.ModelFormField.HyperlinkField;
import org.ofbiz.widget.form.ModelFormField.IgnoredField;
import org.ofbiz.widget.form.ModelFormField.ImageField;
import org.ofbiz.widget.form.ModelFormField.LookupField;
import org.ofbiz.widget.form.ModelFormField.PasswordField;
import org.ofbiz.widget.form.ModelFormField.RadioField;
import org.ofbiz.widget.form.ModelFormField.RangeFindField;
import org.ofbiz.widget.form.ModelFormField.ResetField;
import org.ofbiz.widget.form.ModelFormField.SubmitField;
import org.ofbiz.widget.form.ModelFormField.TextField;
import org.ofbiz.widget.form.ModelFormField.TextFindField;
import org.ofbiz.widget.form.ModelFormField.TextareaField;

import freemarker.template.TemplateException;

/**
* Widget Library - HTML Form Renderer implementation
*/
public class HtmlFormRenderer extends HtmlWidgetRenderer implements FormStringRenderer {

    public static final String module = HtmlFormRenderer.class.getName();

    protected HttpServletRequest request;
    protected HttpServletResponse response;
    protected RequestHandler rh;
    protected String lastFieldGroupId = "";
    protected boolean renderPagination = true;
    protected boolean javaScriptEnabled = false;
    private SimpleEncoder internalEncoder;

    protected HtmlFormRenderer() {}

    public HtmlFormRenderer(HttpServletRequest request, HttpServletResponse response) {
        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 = StringUtil.getEncoder("string");
    }

    public boolean getRenderPagination() {
        return this.renderPagination;
    }

    public void setRenderPagination(boolean renderPagination) {
        this.renderPagination = renderPagination;
    }

    public void appendOfbizUrl(Appendable writer, String location) throws IOException {
        writer.append(this.rh.makeLink(this.request, this.response, location));
    }

    public void appendContentUrl(Appendable writer, String location) throws IOException {
        ContentUrlTag.appendContentPrefix(this.request, writer);
        writer.append(location);
    }

    public void appendTooltip(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        // render the tooltip, in other methods too
        String tooltip = modelFormField.getTooltip(context);
        if (UtilValidate.isNotEmpty(tooltip)) {
            writer.append("<span class=\"");
            String tooltipStyle = modelFormField.getTooltipStyle();
            if (UtilValidate.isNotEmpty(tooltipStyle)) {
                writer.append(tooltipStyle);
            } else {
                writer.append("tooltip");
            }
            writer.append("\">");
            writer.append(tooltip);
            writer.append("</span>");
        }
    }

    public void addAsterisks(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {

        boolean requiredField = modelFormField.getRequiredField();
        if (requiredField) {
            String requiredStyle = modelFormField.getRequiredFieldStyle();

            if (UtilValidate.isEmpty(requiredStyle)) {
               writer.append("*");
            }
        }
    }

    public void appendClassNames(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        String className = modelFormField.getWidgetStyle();
        if (UtilValidate.isNotEmpty(className) || modelFormField.shouldBeRed(context)) {
            writer.append(" class=\"");
            writer.append(className);
            // add a style of red if redWhen is true
            if (modelFormField.shouldBeRed(context)) {
                writer.append(" alert");
            }
            writer.append('"');
        }
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderDisplayField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.DisplayField)
     */
    public void renderDisplayField(Appendable writer, Map<String, Object> context, DisplayField displayField) throws IOException {
        ModelFormField modelFormField = displayField.getModelFormField();

        StringBuilder str = new StringBuilder();

        String idName = modelFormField.getCurrentContainerId(context);

        if (UtilValidate.isNotEmpty(modelFormField.getWidgetStyle()) || modelFormField.shouldBeRed(context)) {
            str.append("<span class=\"");
            str.append(modelFormField.getWidgetStyle());
            // add a style of red if this is a date/time field and redWhen is true
            if (modelFormField.shouldBeRed(context)) {
                str.append(" alert");
            }
            str.append('"');
            if (UtilValidate.isNotEmpty(idName)) {
                str.append(" id=\"");
                str.append(idName+"_sp");
                str.append('"');
            }
            str.append('>');
        }

        if (str.length() > 0) {
            writer.append(str.toString());
        }
        String description = displayField.getDescription(context);
        //Replace new lines with <br/>
        description = description.replaceAll("\n", "<br/>");

        if (UtilValidate.isEmpty(description)) {
            this.renderFormatEmptySpace(writer, context, modelFormField.getModelForm());
        } else {
            writer.append(description);
        }

        if (str.length() > 0) {
            writer.append("</span>");
        }

        ModelFormField.InPlaceEditor inPlaceEditor = displayField.getInPlaceEditor();
        boolean ajaxEnabled = inPlaceEditor != null && this.javaScriptEnabled;

        if (ajaxEnabled) {
            writer.append("<script language=\"JavaScript\" type=\"text/javascript\">");
            StringBuilder url = new StringBuilder(inPlaceEditor.getUrl(context));
            Map<String, Object> fieldMap = inPlaceEditor.getFieldMap(context);
            if (fieldMap != null) {
                url.append('?');
                int count = 0;
                for (Entry<String, Object> field: fieldMap.entrySet()) {
                    count++;
                    url.append(field.getKey()).append('=').append(field.getValue());
                    if (count < fieldMap.size()) {
                        url.append('&');
                    }
                }
            }
            writer.append("ajaxInPlaceEditDisplayField('");
            writer.append(idName).append("', '").append(url).append("', {");
            if (UtilValidate.isNotEmpty(inPlaceEditor.getParamName())) {
                writer.append("name: '").append(inPlaceEditor.getParamName()).append("'");
            } else {
                writer.append("name: '").append(modelFormField.getFieldName()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getCancelControl())) {
                writer.append(", cancelControl: ");
                if (!"false".equals(inPlaceEditor.getCancelControl())) {
                    writer.append("'");
                }
                writer.append(inPlaceEditor.getCancelControl());
                if (!"false".equals(inPlaceEditor.getCancelControl())) {
                    writer.append("'");
                }
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getCancelText())) {
                writer.append(", cancel: '").append(inPlaceEditor.getCancelText()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getClickToEditText())) {
                writer.append(", tooltip: '").append(inPlaceEditor.getClickToEditText()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getFieldPostCreation())) {
                writer.append(", fieldPostCreation: ");
                if (!"false".equals(inPlaceEditor.getFieldPostCreation())) {
                    writer.append("'");
                }
                writer.append(inPlaceEditor.getFieldPostCreation());
                if (!"false".equals(inPlaceEditor.getFieldPostCreation())) {
                    writer.append("'");
                }
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getFormClassName())) {
                writer.append(", cssclass: '").append(inPlaceEditor.getFormClassName()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getHighlightColor())) {
                writer.append(", highlightColor: '").append(inPlaceEditor.getHighlightColor()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getHighlightEndColor())) {
                writer.append(", highlightEndColor: '").append(inPlaceEditor.getHighlightEndColor()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getHoverClassName())) {
                writer.append(", hoverClassName: '").append(inPlaceEditor.getHoverClassName()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getHtmlResponse())) {
                writer.append(", htmlResponse: ").append(inPlaceEditor.getHtmlResponse());
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getLoadingClassName())) {
                writer.append(", loadingClassName: '").append(inPlaceEditor.getLoadingClassName()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getLoadingText())) {
                writer.append(", indicator: '").append(inPlaceEditor.getLoadingText()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getOkControl())) {
                writer.append(", submit: ");
                if (!"false".equals(inPlaceEditor.getOkControl())) {
                    writer.append("'");
                }
                writer.append(inPlaceEditor.getOkControl());
                if (!"false".equals(inPlaceEditor.getOkControl())) {
                    writer.append("'");
                }
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getOkText())) {
                writer.append(", okText: '").append(inPlaceEditor.getOkText()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getSavingClassName())) {
                writer.append(", savingClassName: '").append(inPlaceEditor.getSavingClassName()).append("', ");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getSavingText())) {
                writer.append(", savingText: '").append(inPlaceEditor.getSavingText()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getSubmitOnBlur())) {
                writer.append(", submitOnBlur: ").append(inPlaceEditor.getSubmitOnBlur());
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getTextBeforeControls())) {
                writer.append(", textBeforeControls: '").append(inPlaceEditor.getTextBeforeControls()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getTextAfterControls())) {
                writer.append(", textAfterControls: '").append(inPlaceEditor.getTextAfterControls()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getTextBetweenControls())) {
                writer.append(", textBetweenControls: '").append(inPlaceEditor.getTextBetweenControls()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getUpdateAfterRequestCall())) {
                writer.append(", updateAfterRequestCall: ").append(inPlaceEditor.getUpdateAfterRequestCall());
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getRows())) {
                writer.append(", rows: '").append(inPlaceEditor.getRows()).append("'");
            }
            if (UtilValidate.isNotEmpty(inPlaceEditor.getCols())) {
                writer.append(", cols: '").append(inPlaceEditor.getCols()).append("'");
            }
            writer.append("});");
            writer.append("</script>");
        }

        if (displayField instanceof DisplayEntityField) {
            this.makeHyperlinkString(writer, ((DisplayEntityField) displayField).getSubHyperlink(), context);
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderHyperlinkField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.HyperlinkField)
     */
    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 description = encode(hyperlinkField.getDescription(context), modelFormField, context);
        String confirmation = encode(hyperlinkField.getConfirmation(context), modelFormField, context);
        WidgetWorker.makeHyperlinkByType(writer, hyperlinkField.getLinkType(), modelFormField.getWidgetStyle(), hyperlinkField.getTargetType(), hyperlinkField.getTarget(context),
                hyperlinkField.getParameterMap(context), description, hyperlinkField.getTargetWindow(context), confirmation, modelFormField,
                this.request, this.response, context);
        this.appendTooltip(writer, context, modelFormField);
        //appendWhitespace(writer);
    }

    public void makeHyperlinkString(Appendable writer, ModelFormField.SubHyperlink subHyperlink, Map<String, Object> context) throws IOException {
        if (subHyperlink == null) {
            return;
        }
        if (subHyperlink.shouldUse(context)) {
            writer.append(' ');
            String description = encode(subHyperlink.getDescription(context), subHyperlink.getModelFormField(), context);
            WidgetWorker.makeHyperlinkByType(writer, subHyperlink.getLinkType(), subHyperlink.getLinkStyle(), subHyperlink.getTargetType(), subHyperlink.getTarget(context),
                    subHyperlink.getParameterMap(context), description, subHyperlink.getTargetWindow(context), subHyperlink.getConfirmation(context), subHyperlink.getModelFormField(),
                    this.request, this.response, context);
        }
    }

    private String encode(String value, ModelFormField modelFormField, Map<String, Object> context) {
        if (UtilValidate.isEmpty(value)) {
            return value;
        }
        StringUtil.SimpleEncoder encoder = (StringUtil.SimpleEncoder)context.get("simpleEncoder");
        if (modelFormField.getEncodeOutput() && encoder != null) {
            value = encoder.encode(value);
        } else {
            value = internalEncoder.encode(value);
        }
        return value;
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderTextField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.TextField)
     */
    public void renderTextField(Appendable writer, Map<String, Object> context, TextField textField) throws IOException {
        ModelFormField modelFormField = textField.getModelFormField();

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        String value = modelFormField.getEntry(context, textField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(textField.getSize()));
        writer.append('"');

        Integer maxlength = textField.getMaxlength();
        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        String idName = modelFormField.getCurrentContainerId(context);
        if (UtilValidate.isNotEmpty(idName)) {
            writer.append(" id=\"");
            writer.append(idName);
            writer.append('"');
        }

        String event = modelFormField.getEvent();
        String action = modelFormField.getAction(context);
        if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
            writer.append(" ");
            writer.append(event);
            writer.append("=\"");
            writer.append(action);
            writer.append('"');
        }

        List<ModelForm.UpdateArea> updateAreas = modelFormField.getOnChangeUpdateAreas();
        boolean ajaxEnabled = updateAreas != null && this.javaScriptEnabled;
        if (!textField.getClientAutocompleteField() || ajaxEnabled) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        this.addAsterisks(writer, context, modelFormField);

        this.makeHyperlinkString(writer, textField.getSubHyperlink(), context);

        this.appendTooltip(writer, context, modelFormField);

        if (ajaxEnabled) {
            appendWhitespace(writer);
            writer.append("<script language=\"JavaScript\" type=\"text/javascript\">");
            appendWhitespace(writer);
            writer.append("ajaxAutoCompleter('").append(createAjaxParamsFromUpdateAreas(updateAreas, null, context)).append("');");
            appendWhitespace(writer);
            writer.append("</script>");
        }
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderTextareaField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.TextareaField)
     */
    public void renderTextareaField(Appendable writer, Map<String, Object> context, TextareaField textareaField) throws IOException {
        ModelFormField modelFormField = textareaField.getModelFormField();

        writer.append("<textarea");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        writer.append(" cols=\"");
        writer.append(Integer.toString(textareaField.getCols()));
        writer.append('"');

        writer.append(" rows=\"");
        writer.append(Integer.toString(textareaField.getRows()));
        writer.append('"');

        String idName = modelFormField.getCurrentContainerId(context);
        if (UtilValidate.isNotEmpty(idName)) {
            writer.append(" id=\"");
            writer.append(idName);
            writer.append('"');
        } else if (textareaField.getVisualEditorEnable()) {
            writer.append(" id=\"");
            writer.append("htmlEditArea");
            writer.append('"');
        }

        if (textareaField.isReadOnly()) {
            writer.append(" readonly");
        }

        writer.append('>');

        String value = modelFormField.getEntry(context, textareaField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(value);
        }

        writer.append("</textarea>");

        if (textareaField.getVisualEditorEnable()) {
            writer.append("<script language=\"javascript\" src=\"/images/jquery/plugins/elrteEditor/elrte.min.js\" type=\"text/javascript\"></script>");
            writer.append("<link href=\"/images/jquery/plugins/elrteEditor/css/elrte.full.css\" rel=\"stylesheet\" type=\"text/css\">");
            writer.append("<script language=\"javascript\" type=\"text/javascript\"> var opts = { cssClass : 'el-rte', toolbar : ");
            // define the toolsbar
            String buttons = textareaField.getVisualEditorButtons(context);
            if (UtilValidate.isNotEmpty(buttons)) {
                writer.append(buttons);
            } else {
                writer.append("maxi");
            }
            writer.append(", doctype  : '<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">', //'<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\">'");
            writer.append(", cssfiles : ['/images/jquery/plugins/elrteEditor/css/elrte-inner.css'] ");
            writer.append("}");
            // load the wysiwyg editor
            writer.append("jQuery('#");
            if (UtilValidate.isNotEmpty(idName)) {
                writer.append(idName);
            } else {
                writer.append("htmlEditArea");
            }
            writer.append("').elrte(opts);");
            writer.append("</script>");
        }

        this.addAsterisks(writer, context, modelFormField);

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderDateTimeField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.DateTimeField)
     */
    public void renderDateTimeField(Appendable writer, Map<String, Object> context, DateTimeField dateTimeField) throws IOException {
        String macroLibraryPath = UtilProperties.getPropertyValue("widget", "screen.formrenderer");
        try {
            MacroFormRenderer macroFormRenderer = new MacroFormRenderer(macroLibraryPath, this.request, this.response);
            macroFormRenderer.renderDateTimeField(writer, context, dateTimeField);
        } catch (TemplateException e) {
            Debug.logError(e, "Error rendering screen thru ftl macro: renderDateTimeField", module);
        } catch (IOException e) {
            Debug.logError(e, "Error rendering screen thru ftl, macro: renderDateTimeField", module);
        }
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderDropDownField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.DropDownField)
     */
    public void renderDropDownField(Appendable writer, Map<String, Object> context, DropDownField dropDownField) throws IOException {
        ModelFormField modelFormField = dropDownField.getModelFormField();
        ModelForm modelForm = modelFormField.getModelForm();
        ModelFormField.AutoComplete autoComplete = dropDownField.getAutoComplete();
        boolean ajaxEnabled = autoComplete != null && this.javaScriptEnabled;
        List<ModelFormField.OptionValue> allOptionValues = dropDownField.getAllOptionValues(context, WidgetWorker.getDelegator(context));

        String event = modelFormField.getEvent();
        String action = modelFormField.getAction(context);

        String currentValue = modelFormField.getEntry(context);
        // Get the current value's description from the option value. If there
        // is a localized version it will be there.
        String currentDescription = null;
        if (UtilValidate.isNotEmpty(currentValue)) {
            for (ModelFormField.OptionValue optionValue : allOptionValues) {
                if (encode(optionValue.getKey(), modelFormField, context).equals(currentValue)) {
                    currentDescription = optionValue.getDescription();
                    break;
                }
            }
        }

        if (ajaxEnabled) {
            writer.append("<input type=\"text\"");
        } else {
            writer.append("<select");
        }

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));

        String idName = modelFormField.getCurrentContainerId(context);

        if (ajaxEnabled) {
            writer.append("_description\"");

            String textFieldIdName = idName;
            if (UtilValidate.isNotEmpty(textFieldIdName)) {
                textFieldIdName += "_description";
                writer.append(" id=\"");
                writer.append(textFieldIdName);
                writer.append('"');
            }

            if (UtilValidate.isNotEmpty(currentValue)) {
                writer.append(" value=\"");
                String explicitDescription = null;
                if (currentDescription != null) {
                    explicitDescription = currentDescription;
                } else {
                    explicitDescription = dropDownField.getCurrentDescription(context);
                }
                if (UtilValidate.isEmpty(explicitDescription)) {
                    explicitDescription = ModelFormField.FieldInfoWithOptions.getDescriptionForOptionKey(currentValue, allOptionValues);
                }
                explicitDescription = encode(explicitDescription, modelFormField, context);
                writer.append(explicitDescription);
                writer.append('"');
            }
            writer.append("/>");

            appendWhitespace(writer);
            writer.append("<input type=\"hidden\" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append('"');
            if (UtilValidate.isNotEmpty(idName)) {
                writer.append(" id=\"");
                writer.append(idName);
                writer.append('"');
            }

            if (UtilValidate.isNotEmpty(currentValue)) {
                writer.append(" value=\"");
                //String explicitDescription = dropDownField.getCurrentDescription(context);
                writer.append(currentValue);
                writer.append('"');
            }

            writer.append("/>");

            appendWhitespace(writer);
            writer.append("<script language=\"JavaScript\" type=\"text/javascript\">");
            appendWhitespace(writer);
            writer.append("var data = {");
            int count = 0;
            for (ModelFormField.OptionValue optionValue: allOptionValues) {
                count++;
                writer.append(optionValue.getKey()).append(": ");
                writer.append(" '").append(optionValue.getDescription()).append("'");
                if (count != allOptionValues.size()) {
                    writer.append(", ");
                }
            }
            writer.append("};");
            appendWhitespace(writer);
            writer.append("ajaxAutoCompleteDropDown('").append(textFieldIdName).append("', '").append(idName).append("', data, {autoSelect: ").append(
                    autoComplete.getAutoSelect()).append(", frequency: ").append(autoComplete.getFrequency()).append(", minChars: ").append(autoComplete.getMinChars()).append(
                    ", choices: ").append(autoComplete.getChoices()).append(", partialSearch: ").append(autoComplete.getPartialSearch()).append(
                    ", partialChars: ").append(autoComplete.getPartialChars()).append(", ignoreCase: ").append(autoComplete.getIgnoreCase()).append(
                    ", fullSearch: ").append(autoComplete.getFullSearch()).append("});");
            appendWhitespace(writer);
            writer.append("</script>");
        } else {
            writer.append('"');

            if (UtilValidate.isNotEmpty(idName)) {
                writer.append(" id=\"");
                writer.append(idName);
                writer.append('"');
            }

            if (dropDownField.isAllowMultiple()) {
                writer.append(" multiple=\"multiple\"");
            }

            int otherFieldSize = dropDownField.getOtherFieldSize();
            String otherFieldName = dropDownField.getParameterNameOther(context);
            if (otherFieldSize > 0) {
                //writer.append(" onchange=\"alert('ONCHANGE, process_choice:' + process_choice)\"");
                //writer.append(" onchange='test_js()' ");
                writer.append(" onchange=\"process_choice(this,document.");
                writer.append(modelForm.getName());
                writer.append(".");
                writer.append(otherFieldName);
                writer.append(")\" ");
            }

            if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
                writer.append(" ");
                writer.append(event);
                writer.append("=\"");
                writer.append(action);
                writer.append('"');
            }

            writer.append(" size=\"").append(dropDownField.getSize()).append("\">");

            // if the current value should go first, stick it in
            if (UtilValidate.isNotEmpty(currentValue) && "first-in-list".equals(dropDownField.getCurrent())) {
                writer.append("<option");
                writer.append(" selected=\"selected\"");
                writer.append(" value=\"");
                writer.append(currentValue);
                writer.append("\">");
                String explicitDescription = (currentDescription != null ? currentDescription : dropDownField.getCurrentDescription(context));
                if (UtilValidate.isNotEmpty(explicitDescription)) {
                    writer.append(encode(explicitDescription, modelFormField, context));
                } else {
                    String description = ModelFormField.FieldInfoWithOptions.getDescriptionForOptionKey(currentValue, allOptionValues);
                    writer.append(encode(description, modelFormField, context));
                }
                writer.append("</option>");

                // add a "separator" option
                writer.append("<option value=\"");
                writer.append(currentValue);
                writer.append("\">---</option>");
            }

            // if allow empty is true, add an empty option
            if (dropDownField.isAllowEmpty()) {
                writer.append("<option value=\"\">&nbsp;</option>");
            }

            // list out all options according to the option list
            for (ModelFormField.OptionValue optionValue: allOptionValues) {
                String noCurrentSelectedKey = dropDownField.getNoCurrentSelectedKey(context);
                writer.append("<option");
                // if current value should be selected in the list, select it
                if (UtilValidate.isNotEmpty(currentValue) && currentValue.equals(optionValue.getKey()) && "selected".equals(dropDownField.getCurrent())) {
                    writer.append(" selected=\"selected\"");
                } else if (UtilValidate.isEmpty(currentValue) && noCurrentSelectedKey != null && noCurrentSelectedKey.equals(optionValue.getKey())) {
                    writer.append(" selected=\"selected\"");
                }
                writer.append(" value=\"");
                writer.append(encode(optionValue.getKey(), modelFormField, context));
                writer.append("\">");
                writer.append(encode(optionValue.getDescription(), modelFormField, context));
                writer.append("</option>");
            }

            writer.append("</select>");


            // Adapted from work by Yucca Korpela
            // http://www.cs.tut.fi/~jkorpela/forms/combo.html
            if (otherFieldSize > 0) {

                String fieldName = modelFormField.getParameterName(context);
                Map<String, Object> dataMap = UtilGenerics.checkMap(modelFormField.getMap(context));
                if (dataMap == null) {
                    dataMap = context;
                }
                Object otherValueObj = dataMap.get(otherFieldName);
                String otherValue = (otherValueObj == null) ? "" : otherValueObj.toString();

                writer.append("<noscript>");
                writer.append("<input type='text' name='");
                writer.append(otherFieldName);
                writer.append("'/> ");
                writer.append("</noscript>");
                writer.append("\n<script type='text/javascript' language='JavaScript'><!--");
                writer.append("\ndisa = ' disabled';");
                writer.append("\nif (other_choice(document.");
                writer.append(modelForm.getName());
                writer.append(".");
                writer.append(fieldName);
                writer.append(")) disa = '';");
                writer.append("\ndocument.write(\"<input type=");
                writer.append("'text' name='");
                writer.append(otherFieldName);
                writer.append("' value='");
                writer.append(otherValue);
                writer.append("' size='");
                writer.append(Integer.toString(otherFieldSize));
                writer.append("' ");
                writer.append("\" +disa+ \" onfocus='check_choice(document.");
                writer.append(modelForm.getName());
                writer.append(".");
                writer.append(fieldName);
                writer.append(")'/>\");");
                writer.append("\nif (disa && document.styleSheets)");
                writer.append(" document.");
                writer.append(modelForm.getName());
                writer.append(".");
                writer.append(otherFieldName);
                writer.append(".style.visibility  = 'hidden';");
                writer.append("\n//--></script>");
            }
        }

        this.makeHyperlinkString(writer, dropDownField.getSubHyperlink(), context);

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderCheckField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.CheckField)
     */
    public void renderCheckField(Appendable writer, Map<String, Object> context, CheckField checkField) throws IOException {
        ModelFormField modelFormField = checkField.getModelFormField();
        String currentValue = modelFormField.getEntry(context);
        Boolean allChecked = checkField.isAllChecked(context);

        List<ModelFormField.OptionValue> allOptionValues = checkField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
        String event = modelFormField.getEvent();
        String action = modelFormField.getAction(context);

        // list out all options according to the option list
        for (ModelFormField.OptionValue optionValue: allOptionValues) {

            writer.append("<input type=\"checkbox\"");

            appendClassNames(writer, context, modelFormField);

            // if current value should be selected in the list, select it
            if (Boolean.TRUE.equals(allChecked)) {
                writer.append(" checked=\"checked\"");
            } else if (Boolean.FALSE.equals(allChecked)) {
                // do nothing
            } else if (UtilValidate.isNotEmpty(currentValue) && currentValue.equals(optionValue.getKey())) {
                writer.append(" checked=\"checked\"");
            }
            writer.append(" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append('"');
            writer.append(" value=\"");
            writer.append(encode(optionValue.getKey(), modelFormField, context));
            writer.append("\"");

            if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
                writer.append(" ");
                writer.append(event);
                writer.append("=\"");
                writer.append(action);
                writer.append('"');
            }

            writer.append("/>");

            writer.append(encode(optionValue.getDescription(), modelFormField, context));
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderRadioField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.RadioField)
     */
    public void renderRadioField(Appendable writer, Map<String, Object> context, RadioField radioField) throws IOException {
        ModelFormField modelFormField = radioField.getModelFormField();
        List<ModelFormField.OptionValue> allOptionValues = radioField.getAllOptionValues(context, WidgetWorker.getDelegator(context));
        String currentValue = modelFormField.getEntry(context);
        String event = modelFormField.getEvent();
        String action = modelFormField.getAction(context);

        // list out all options according to the option list
        for (ModelFormField.OptionValue optionValue: allOptionValues) {

            writer.append("<span");

            appendClassNames(writer, context, modelFormField);

            writer.append("><input type=\"radio\"");

            // if current value should be selected in the list, select it
            String noCurrentSelectedKey = radioField.getNoCurrentSelectedKey(context);
            if (UtilValidate.isNotEmpty(currentValue) && currentValue.equals(optionValue.getKey())) {
                writer.append(" checked=\"checked\"");
            } else if (UtilValidate.isEmpty(currentValue) && noCurrentSelectedKey != null && noCurrentSelectedKey.equals(optionValue.getKey())) {
                writer.append(" checked=\"checked\"");
            }
            writer.append(" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append('"');
            writer.append(" value=\"");
            writer.append(encode(optionValue.getKey(), modelFormField, context));
            writer.append("\"");

            if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
                writer.append(" ");
                writer.append(event);
                writer.append("=\"");
                writer.append(action);
                writer.append('"');
            }

            writer.append("/>");

            writer.append(encode(optionValue.getDescription(), modelFormField, context));
            writer.append("</span>");
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderSubmitField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.SubmitField)
     */
    public void renderSubmitField(Appendable writer, Map<String, Object> context, SubmitField submitField) throws IOException {
        ModelFormField modelFormField = submitField.getModelFormField();
        ModelForm modelForm = modelFormField.getModelForm();
        String event = null;
        String action = null;
        String confirmation =  encode(submitField.getConfirmation(context), modelFormField, context);

        if ("text-link".equals(submitField.getButtonType())) {
            writer.append("<a");

            appendClassNames(writer, context, modelFormField);
            if (UtilValidate.isNotEmpty(confirmation)) {
                writer.append(" onclick=\"return confirm('");
                writer.append(confirmation);
                writer.append("'); \" ");
            }

            writer.append(" href=\"javascript:document.");
            writer.append(modelForm.getCurrentFormName(context));
            writer.append(".submit()\">");

            writer.append(encode(modelFormField.getTitle(context), modelFormField, context));

            writer.append("</a>");
        } else if ("image".equals(submitField.getButtonType())) {
            writer.append("<input type=\"image\"");

            appendClassNames(writer, context, modelFormField);

            writer.append(" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append('"');

            String title = modelFormField.getTitle(context);
            if (UtilValidate.isNotEmpty(title)) {
                writer.append(" alt=\"");
                writer.append(encode(title, modelFormField, context));
                writer.append('"');
            }

            writer.append(" src=\"");
            this.appendContentUrl(writer, submitField.getImageLocation(context));
            writer.append('"');

            event = modelFormField.getEvent();
            action = modelFormField.getAction(context);
            if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
                writer.append(" ");
                writer.append(event);
                writer.append("=\"");
                writer.append(action);
                writer.append('"');
            }

            if (UtilValidate.isNotEmpty(confirmation)) {
                writer.append("onclick=\" return confirm('");
                writer.append(confirmation);
                writer.append("); \" ");
            }

            writer.append("/>");
        } else {
            // default to "button"

            String formId = modelForm.getContainerId();
            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 = FastList.newInstance();
                }
                updateAreas.add(new ModelForm.UpdateArea("submit", formId, backgroundSubmitRefreshTarget));
            }

            boolean ajaxEnabled = (updateAreas != null || UtilValidate.isNotEmpty(backgroundSubmitRefreshTarget)) && this.javaScriptEnabled;
            if (ajaxEnabled) {
                writer.append("<input type=\"button\"");
            } else {
                writer.append("<input type=\"submit\"");
            }

            appendClassNames(writer, context, modelFormField);

            writer.append(" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append('"');

            String title = modelFormField.getTitle(context);
            if (UtilValidate.isNotEmpty(title)) {
                writer.append(" value=\"");
                writer.append(encode(title, modelFormField, context));
                writer.append('"');
            }


            event = modelFormField.getEvent();
            action = modelFormField.getAction(context);
            if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
                writer.append(" ");
                writer.append(event);
                writer.append("=\"");
                writer.append(action);
                writer.append('"');
            } else {
                //add single click JS onclick
                // disabling for now, using form onSubmit action instead: writer.append(singleClickAction);
            }

            if (ajaxEnabled) {
                writer.append(" onclick=\"");
                if (UtilValidate.isNotEmpty(confirmation)) {
                    writer.append("if  (confirm('");
                    writer.append(confirmation);
                    writer.append(");) ");
                }
                writer.append("ajaxSubmitFormUpdateAreas('");
                writer.append(formId);
                writer.append("', '").append(createAjaxParamsFromUpdateAreas(updateAreas, null, context));
                writer.append("')\"");
            }

            writer.append("/>");
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderResetField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.ResetField)
     */
    public void renderResetField(Appendable writer, Map<String, Object> context, ResetField resetField) throws IOException {
        ModelFormField modelFormField = resetField.getModelFormField();

        writer.append("<input type=\"reset\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        String title = modelFormField.getTitle(context);
        if (UtilValidate.isNotEmpty(title)) {
            writer.append(" value=\"");
            writer.append(encode(title, modelFormField, context));
            writer.append('"');
        }

        writer.append("/>");

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderHiddenField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.HiddenField)
     */
    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 {
        writer.append("<input type=\"hidden\"");

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append("/>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderIgnoredField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.IgnoredField)
     */
    public void renderIgnoredField(Appendable writer, Map<String, Object> context, IgnoredField ignoredField) throws IOException {
        // do nothing, it's an ignored field; could add a comment or something if we wanted to
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFieldTitle(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFieldTitle(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        String tempTitleText = modelFormField.getTitle(context);
        String titleText = UtilHttp.encodeAmpersands(tempTitleText);

        if (UtilValidate.isNotEmpty(titleText)) {
            if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
                writer.append("<span class=\"");
                writer.append(modelFormField.getTitleStyle());
                writer.append("\">");
            }
            if (" ".equals(titleText)) {
                // If the title content is just a blank then render it colling renderFormatEmptySpace:
                // the method will set its content to work fine in most browser
                this.renderFormatEmptySpace(writer, context, modelFormField.getModelForm());
            } else {
                renderHyperlinkTitle(writer, context, modelFormField, titleText);
            }

            if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
                writer.append("</span>");
            }

            //appendWhitespace(writer);
        }
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFieldTitle(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderSingleFormFieldTitle(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        boolean requiredField = modelFormField.getRequiredField();
        if (requiredField) {

            String requiredStyle = modelFormField.getRequiredFieldStyle();
            if (UtilValidate.isEmpty(requiredStyle)) {
                requiredStyle = modelFormField.getTitleStyle();
            }

            if (UtilValidate.isNotEmpty(requiredStyle)) {
                writer.append("<span class=\"");
                writer.append(requiredStyle);
                writer.append("\">");
            }
            renderHyperlinkTitle(writer, context, modelFormField, modelFormField.getTitle(context));
            if (UtilValidate.isNotEmpty(requiredStyle)) {
                writer.append("</span>");
            }

            //appendWhitespace(writer);
        } else {
            renderFieldTitle(writer, context, modelFormField);
        }
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    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);
        writer.append("<form method=\"post\" ");
        String targetType = modelForm.getTargetType();
        String targ = modelForm.getTarget(context, targetType);
        // The 'action' attribute is mandatory in a form definition,
        // even if it is empty.
        writer.append(" action=\"");
        if (UtilValidate.isNotEmpty(targ)) {
            //this.appendOfbizUrl(writer, "/" + targ);
            WidgetWorker.buildHyperlinkUrl(writer, targ, targetType, null, null, false, false, true, request, response, context);
        }
        writer.append("\" ");

        String formType = modelForm.getType();
        if (formType.equals("upload")) {
            writer.append(" enctype=\"multipart/form-data\"");
        }

        String targetWindow = modelForm.getTargetWindow(context);
        if (UtilValidate.isNotEmpty(targetWindow)) {
            writer.append(" target=\"");
            writer.append(targetWindow);
            writer.append("\"");
        }

        String containerId =  modelForm.getCurrentContainerId(context);
        if (UtilValidate.isNotEmpty(containerId)) {
            writer.append(" id=\"");
            writer.append(containerId);
            writer.append("\"");
        }

        writer.append(" class=\"");
        String containerStyle =  modelForm.getContainerStyle();
        if (UtilValidate.isNotEmpty(containerStyle)) {
            writer.append(containerStyle);
        } else {
            writer.append("basic-form");
        }
        writer.append("\"");

        writer.append(" onsubmit=\"javascript:submitFormDisableSubmits(this)\"");

        if (!modelForm.getClientAutocompleteFields()) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append(" name=\"");
        writer.append(modelForm.getCurrentFormName(context));
        writer.append("\">");

        boolean useRowSubmit = modelForm.getUseRowSubmit();
        if (useRowSubmit) {
            writer.append("<input type=\"hidden\" name=\"_useRowSubmit\" value=\"Y\"/>");
        }

        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("</form>");
        String focusFieldName = modelForm.getfocusFieldName();
        if (UtilValidate.isNotEmpty(focusFieldName)) {
            appendWhitespace(writer);
            writer.append("<script language=\"JavaScript\" type=\"text/javascript\">");
            appendWhitespace(writer);
            writer.append("document.").append(modelForm.getCurrentFormName(context)).append(".");
            writer.append(focusFieldName).append(".focus();");
            appendWhitespace(writer);
            writer.append("</script>");
        }
        appendWhitespace(writer);
        renderEndingBoundaryComment(writer, "Form Widget - Form Element", modelForm);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderMultiFormClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        for (ModelFormField submitField: modelForm.getMultiSubmitFields()) {
            if (submitField != null) {

                // 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);

            }
        }
        writer.append("</form>");
        appendWhitespace(writer);

        // 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);

        this.widgetCommentsEnabled = ModelWidget.widgetBoundaryCommentsEnabled(context);
        renderBeginningBoundaryComment(writer, "Form Widget", modelForm);

        if (this.renderPagination) {
            this.renderNextPrev(writer, context, modelForm);
        }
        writer.append(" <table cellspacing=\"0\" class=\"");
        if (UtilValidate.isNotEmpty(modelForm.getDefaultTableStyle())) {
            writer.append(FlexibleStringExpander.expandString(modelForm.getDefaultTableStyle(), context));
        } else {
            writer.append("basic-table form-widget-table dark-grid");
        }
        writer.append("\">");
        appendWhitespace(writer);
    }

    public void renderFormatListWrapperClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append(" </table>");

        appendWhitespace(writer);
        if (this.renderPagination) {
            this.renderNextPrev(writer, context, modelForm);
        }
        renderEndingBoundaryComment(writer, "Form Widget - Formal List Wrapper", modelForm);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatHeaderRowOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatHeaderRowOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("  <tr");
        String headerStyle = FlexibleStringExpander.expandString(modelForm.getHeaderRowStyle(), context);
        writer.append(" class=\"");
        if (UtilValidate.isNotEmpty(headerStyle)) {
            writer.append(headerStyle);
        } else {
            writer.append("header-row");
        }
        writer.append("\">");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatHeaderRowClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatHeaderRowClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("  </tr>");

        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatHeaderRowCellOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm, org.ofbiz.widget.form.ModelFormField, int positionSpan)
     */
    public void renderFormatHeaderRowCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField, int positionSpan) throws IOException {
        writer.append("   <td");
        String areaStyle = modelFormField.getTitleAreaStyle();
        if (positionSpan > 1) {
            writer.append(" colspan=\"");
            writer.append(Integer.toString(positionSpan));
            writer.append("\"");
        }
        if (UtilValidate.isNotEmpty(areaStyle)) {
            writer.append(" class=\"");
            writer.append(areaStyle);
            writer.append("\"");
        }
        writer.append(">");
        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatHeaderRowCellClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFormatHeaderRowCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField) throws IOException {
        writer.append("</td>");
        appendWhitespace(writer);
    }

    public void renderFormatHeaderRowFormCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("   <td");
        String areaStyle = modelForm.getFormTitleAreaStyle();
        if (UtilValidate.isNotEmpty(areaStyle)) {
            writer.append(" class=\"");
            writer.append(areaStyle);
            writer.append("\"");
        }
        writer.append(">");
        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatHeaderRowFormCellClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatHeaderRowFormCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("</td>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatHeaderRowFormCellTitleSeparator(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm, boolean)
     */
    public void renderFormatHeaderRowFormCellTitleSeparator(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField, boolean isLast) throws IOException {

        String titleStyle = modelFormField.getTitleStyle();
        if (UtilValidate.isNotEmpty(titleStyle)) {
            writer.append("<span class=\"");
            writer.append(titleStyle);
            writer.append("\">");
        }
        if (isLast) {
            writer.append(" - ");
        } else {
            writer.append(" - ");
        }
        if (UtilValidate.isNotEmpty(titleStyle)) {
            writer.append("</span>");
        }
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatItemRowOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatItemRowOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        Integer itemIndex = (Integer)context.get("itemIndex");

        writer.append("  <tr");
        if (itemIndex!=null) {

            String altRowStyles = modelForm.getStyleAltRowStyle(context);
            if (itemIndex.intValue() % 2 == 0) {
                String evenRowStyle = modelForm.getEvenRowStyle();
                if (UtilValidate.isNotEmpty(evenRowStyle)) {
                    writer.append(" class=\"");
                    writer.append(evenRowStyle);
                    if (UtilValidate.isNotEmpty(altRowStyles)) {
                        writer.append(altRowStyles);
                    }
                    writer.append("\"");
                } else {
                    if (UtilValidate.isNotEmpty(altRowStyles)) {
                        writer.append(" class=\"");
                        writer.append(altRowStyles);
                        writer.append("\"");
                    }
                }
            } else {
                String oddRowStyle = FlexibleStringExpander.expandString(modelForm.getOddRowStyle(), context);
                if (UtilValidate.isNotEmpty(oddRowStyle)) {
                    writer.append(" class=\"");
                    writer.append(oddRowStyle);
                    if (UtilValidate.isNotEmpty(altRowStyles)) {
                        writer.append(altRowStyles);
                    }
                    writer.append("\"");
                } else {
                    if (UtilValidate.isNotEmpty(altRowStyles)) {
                        writer.append(" class=\"");
                        writer.append(altRowStyles);
                        writer.append("\"");
                    }
                }
            }
        }
        writer.append(">");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatItemRowClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatItemRowClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("  </tr>");

        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatItemRowCellOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFormatItemRowCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField, int positionSpan) throws IOException {
        writer.append("   <td");
        String areaStyle = modelFormField.getWidgetAreaStyle();
        if (positionSpan > 1) {
            writer.append(" colspan=\"");
            writer.append(Integer.toString(positionSpan));
            writer.append("\"");
        }
        if (UtilValidate.isNotEmpty(areaStyle)) {
            writer.append(" class=\"");
            writer.append(areaStyle);
            writer.append("\"");
        }
        writer.append(">");
        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatItemRowCellClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFormatItemRowCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm, ModelFormField modelFormField) throws IOException {
        writer.append("</td>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatItemRowFormCellOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatItemRowFormCellOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("   <td");
        String areaStyle = modelForm.getFormWidgetAreaStyle();
        if (UtilValidate.isNotEmpty(areaStyle)) {
            writer.append(" class=\"");
            writer.append(areaStyle);
            writer.append("\"");
        }
        writer.append(">");
        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatItemRowFormCellClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatItemRowFormCellClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("</td>");
        appendWhitespace(writer);
    }

    public void renderFormatSingleWrapperOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append(" <table cellspacing=\"0\"");
        if (UtilValidate.isNotEmpty(modelForm.getDefaultTableStyle())) {
            writer.append(" class=\"").append(FlexibleStringExpander.expandString(modelForm.getDefaultTableStyle(), context)).append("\"");
        }
        writer.append(">");
        appendWhitespace(writer);
    }

    public void renderFormatSingleWrapperClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append(" </table>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatFieldRowOpen(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("  <tr>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelForm)
     */
    public void renderFormatFieldRowClose(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("  </tr>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowTitleCellOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFormatFieldRowTitleCellOpen(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        writer.append("   <td");
        String areaStyle = modelFormField.getTitleAreaStyle();
        if (UtilValidate.isNotEmpty(areaStyle)) {
            writer.append(" class=\"");
            writer.append(areaStyle);
            writer.append("\"");
        } else {
            writer.append(" class=\"label\"");
        }
        writer.append(">");
        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowTitleCellClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFormatFieldRowTitleCellClose(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        writer.append("</td>");
        appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowSpacerCell(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField)
     */
    public void renderFormatFieldRowSpacerCell(Appendable writer, Map<String, Object> context, ModelFormField modelFormField) throws IOException {
        // Embedded styling - bad idea
        //writer.append("<td>&nbsp;</td>");

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowWidgetCellOpen(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField, int)
     */
    public void renderFormatFieldRowWidgetCellOpen(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, int positions, int positionSpan, Integer nextPositionInRow) throws IOException {
//        writer.append("<td width=\"");
//        if (nextPositionInRow != null || modelFormField.getPosition() > 1) {
//            writer.append("30");
//        } else {
//            writer.append("80");
//        }
//        writer.append("%\"");
        writer.append("   <td");
        if (positionSpan > 0) {
            writer.append(" colspan=\"");
            // do a span of 1 for this column, plus 3 columns for each spanned
            //position or each blank position that this will be filling in
            writer.append(Integer.toString(1 + (positionSpan * 3)));
            writer.append("\"");
        }
        String areaStyle = modelFormField.getWidgetAreaStyle();
        if (UtilValidate.isNotEmpty(areaStyle)) {
            writer.append(" class=\"");
            writer.append(areaStyle);
            writer.append("\"");
        }
        writer.append(">");

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFormatFieldRowWidgetCellClose(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField, int)
     */
    public void renderFormatFieldRowWidgetCellClose(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, int positions, int positionSpan, Integer nextPositionInRow) throws IOException {
        writer.append("</td>");
        appendWhitespace(writer);
    }

    public void renderFormatEmptySpace(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        writer.append("&nbsp;");
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderTextFindField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.TextFindField)
     */
    public void renderTextFindField(Appendable writer, Map<String, Object> context, TextFindField textFindField) throws IOException {

        ModelFormField modelFormField = textFindField.getModelFormField();

        String defaultOption = textFindField.getDefaultOption();
        Locale locale = (Locale)context.get("locale");
        if (!textFindField.getHideOptions()) {
            String opEquals = UtilProperties.getMessage("conditional", "equals", locale);
            String opBeginsWith = UtilProperties.getMessage("conditional", "begins_with", locale);
            String opContains = UtilProperties.getMessage("conditional", "contains", locale);
            String opIsEmpty = UtilProperties.getMessage("conditional", "is_empty", locale);
            String opNotEqual = UtilProperties.getMessage("conditional", "not_equal", locale);
            writer.append(" <select name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append("_op\" class=\"selectBox\">");
            writer.append("<option value=\"equals\"").append(("equals".equals(defaultOption)? " selected": "")).append(">").append(opEquals).append("</option>");
            writer.append("<option value=\"like\"").append(("like".equals(defaultOption)? " selected": "")).append(">").append(opBeginsWith).append("</option>");
            writer.append("<option value=\"contains\"").append(("contains".equals(defaultOption)? " selected": "")).append(">").append(opContains).append("</option>");
            writer.append("<option value=\"empty\"").append(("empty".equals(defaultOption)? " selected": "")).append(">").append(opIsEmpty).append("</option>");
            writer.append("<option value=\"notEqual\"").append(("notEqual".equals(defaultOption)? " selected": "")).append(">").append(opNotEqual).append("</option>");
            writer.append("</select>");
        } else {
            writer.append(" <input type=\"hidden\" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append("_op\" value=\"").append(defaultOption).append("\"/>");
        }

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        String value = modelFormField.getEntry(context, textFindField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(textFindField.getSize()));
        writer.append('"');

        Integer maxlength = textFindField.getMaxlength();
        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        if (!textFindField.getClientAutocompleteField()) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append(" <span class=\"");
            writer.append(modelFormField.getTitleStyle());
            writer.append("\">");
        }

        String ignoreCase = UtilProperties.getMessage("conditional", "ignore_case", locale);
        boolean ignCase = textFindField.getIgnoreCase();

        if (!textFindField.getHideIgnoreCase()) {
            writer.append(" <input type=\"checkbox\" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append("_ic\" value=\"Y\"").append((ignCase ? " checked=\"checked\"" : "")).append("/>");
            writer.append(ignoreCase);
        } else {
            writer.append("<input type=\"hidden\" name=\"");
            writer.append(modelFormField.getParameterName(context));
            writer.append("_ic\" value=\"").append((ignCase ? "Y" : "")).append("\"/>");
        }

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append("</span>");
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderRangeFindField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.RangeFindField)
     */
    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);

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld0_value\"");

        String value = modelFormField.getEntry(context, rangeFindField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(rangeFindField.getSize()));
        writer.append('"');

        Integer maxlength = rangeFindField.getMaxlength();
        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        if (!rangeFindField.getClientAutocompleteField()) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append(" <span class=\"");
            writer.append(modelFormField.getTitleStyle());
            writer.append("\">");
        }

        String defaultOptionFrom = rangeFindField.getDefaultOptionFrom();
        writer.append(" <select name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld0_op\" class=\"selectBox\">");
        writer.append("<option value=\"equals\"").append(("equals".equals(defaultOptionFrom)? " selected": "")).append(">").append(opEquals).append("</option>");
        writer.append("<option value=\"greaterThan\"").append(("greaterThan".equals(defaultOptionFrom)? " selected": "")).append(">").append(opGreaterThan).append("</option>");
        writer.append("<option value=\"greaterThanEqualTo\"").append(("greaterThanEqualTo".equals(defaultOptionFrom)? " selected": "")).append(">").append(opGreaterThanEquals).append("</option>");
        writer.append("</select>");

        writer.append("</span>");

        writer.append(" <br/> ");

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld1_value\"");

        value = modelFormField.getEntry(context);
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(rangeFindField.getSize()));
        writer.append('"');

        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        if (!rangeFindField.getClientAutocompleteField()) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        String defaultOptionThru = rangeFindField.getDefaultOptionThru();
        writer.append(" <select name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld1_op\" class=\"selectBox\">");
        writer.append("<option value=\"lessThan\"").append(("lessThan".equals(defaultOptionThru)? " selected": "")).append(">").append(opLessThan).append("</option>");
        writer.append("<option value=\"lessThanEqualTo\"").append(("lessThanEqualTo".equals(defaultOptionThru)? " selected": "")).append(">").append(opLessThanEquals).append("</option>");
        writer.append("</select>");

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append("</span>");
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderDateFindField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.DateFindField)
     */
    public void renderDateFindField(Appendable writer, Map<String, Object> context, DateFindField dateFindField) throws IOException {
        ModelFormField modelFormField = dateFindField.getModelFormField();

        Locale locale = (Locale)context.get("locale");
        String opEquals = UtilProperties.getMessage("conditional", "equals", locale);
        String opGreaterThan = UtilProperties.getMessage("conditional", "greater_than", locale);
        String opSameDay = UtilProperties.getMessage("conditional", "same_day", locale);
        String opGreaterThanFromDayStart = UtilProperties.getMessage("conditional",
                                                "greater_than_from_day_start", locale);
        String opLessThan = UtilProperties.getMessage("conditional", "less_than", locale);
        String opUpToDay = UtilProperties.getMessage("conditional", "up_to_day", locale);
        String opUpThruDay = UtilProperties.getMessage("conditional", "up_thru_day", locale);
        String opIsEmpty = UtilProperties.getMessage("conditional", "is_empty", locale);

        Map<String, String> uiLabelMap = UtilGenerics.checkMap(context.get("uiLabelMap"));
        if (uiLabelMap == null) {
            Debug.logWarning("Could not find uiLabelMap in context", module);
        }
        String localizedInputTitle = "", localizedIconTitle = "";

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld0_value\"");

        // the default values for a timestamp
        int size = 25;
        int maxlength = 30;

        if ("date".equals(dateFindField.getType())) {
            size = maxlength = 10;
            if (uiLabelMap != null) {
                localizedInputTitle = uiLabelMap.get("CommonFormatDate");
            }
        } else if ("time".equals(dateFindField.getType())) {
            size = maxlength = 8;
            if (uiLabelMap != null) {
                localizedInputTitle = uiLabelMap.get("CommonFormatTime");
            }
        } else {
            if (uiLabelMap != null) {
                localizedInputTitle = uiLabelMap.get("CommonFormatDateTime");
            }
        }
        writer.append(" title=\"");
        writer.append(localizedInputTitle);
        writer.append('"');

        String value = modelFormField.getEntry(context, dateFindField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            if (value.length() > maxlength) {
                value = value.substring(0, maxlength);
            }
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(size));
        writer.append('"');

        writer.append(" maxlength=\"");
        writer.append(Integer.toString(maxlength));
        writer.append('"');

        writer.append("/>");

        // search for a localized label for the icon
        if (uiLabelMap != null) {
            localizedIconTitle = uiLabelMap.get("CommonViewCalendar");
        }

        // add calendar pop-up button and seed data IF this is not a "time" type date-find
        if (!"time".equals(dateFindField.getType())) {
            if ("date".equals(dateFindField.getType())) {
                writer.append("<a href=\"javascript:call_cal_notime(document.");
            } else {
                writer.append("<a href=\"javascript:call_cal(document.");
            }
            writer.append(modelFormField.getModelForm().getCurrentFormName(context));
            writer.append('.');
            writer.append(modelFormField.getParameterName(context));
            writer.append("_fld0_value,'");
            writer.append(UtilHttp.encodeBlanks(modelFormField.getEntry(context, dateFindField.getDefaultDateTimeString(context))));
            writer.append("');\">");

            writer.append("<img src=\"");
            this.appendContentUrl(writer, "/images/cal.gif");
            writer.append("\" width=\"16\" height=\"16\" border=\"0\" alt=\"");
            writer.append(localizedIconTitle);
            writer.append("\" title=\"");
            writer.append(localizedIconTitle);
            writer.append("\"/></a>");
        }

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append(" <span class=\"");
            writer.append(modelFormField.getTitleStyle());
            writer.append("\">");
        }

        String defaultOptionFrom = dateFindField.getDefaultOptionFrom();
        writer.append(" <select name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld0_op\" class=\"selectBox\">");
        writer.append("<option value=\"equals\"").append(("equals".equals(defaultOptionFrom)? " selected": "")).append(">").append(opEquals).append("</option>");
        writer.append("<option value=\"sameDay\"").append(("sameDay".equals(defaultOptionFrom)? " selected": "")).append(">").append(opSameDay).append("</option>");
        writer.append("<option value=\"greaterThanFromDayStart\"").append(("greaterThanFromDayStart".equals(defaultOptionFrom)? " selected": "")).append(">").append(opGreaterThanFromDayStart).append("</option>");
        writer.append("<option value=\"greaterThan\"").append(("greaterThan".equals(defaultOptionFrom)? " selected": "")).append(">").append(opGreaterThan).append("</option>");
        writer.append("</select>");

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append(" </span>");
        }

        writer.append(" <br/> ");

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld1_value\"");

        writer.append(" title=\"");
        writer.append(localizedInputTitle);
        writer.append('"');

        value = modelFormField.getEntry(context);
        if (UtilValidate.isNotEmpty(value)) {
            if (value.length() > maxlength) {
                value = value.substring(0, maxlength);
            }
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(size));
        writer.append('"');

        writer.append(" maxlength=\"");
        writer.append(Integer.toString(maxlength));
        writer.append('"');

        writer.append("/>");

        // add calendar pop-up button and seed data IF this is not a "time" type date-find
        if (!"time".equals(dateFindField.getType())) {
            if ("date".equals(dateFindField.getType())) {
                writer.append("<a href=\"javascript:call_cal_notime(document.");
            } else {
                writer.append("<a href=\"javascript:call_cal(document.");
            }
            writer.append(modelFormField.getModelForm().getCurrentFormName(context));
            writer.append('.');
            writer.append(modelFormField.getParameterName(context));
            writer.append("_fld1_value,'");
            writer.append(UtilHttp.encodeBlanks(modelFormField.getEntry(context, dateFindField.getDefaultDateTimeString(context))));
            writer.append("');\">");

            writer.append("<img src=\"");
            this.appendContentUrl(writer, "/images/cal.gif");
            writer.append("\" width=\"16\" height=\"16\" border=\"0\" alt=\"");
            writer.append(localizedIconTitle);
            writer.append("\" title=\"");
            writer.append(localizedIconTitle);
            writer.append("\"/></a>");
        }

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append(" <span class=\"");
            writer.append(modelFormField.getTitleStyle());
            writer.append("\">");
        }

        String defaultOptionThru = dateFindField.getDefaultOptionThru();
        writer.append(" <select name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append("_fld1_op\" class=\"selectBox\">");
        writer.append("<option value=\"lessThan\"").append(("lessThan".equals(defaultOptionThru)? " selected": "")).append(">").append(opLessThan).append("</option>");
        writer.append("<option value=\"upToDay\"").append(("upToDay".equals(defaultOptionThru)? " selected": "")).append(">").append(opUpToDay).append("</option>");
        writer.append("<option value=\"upThruDay\"").append(("upThruDay".equals(defaultOptionThru)? " selected": "")).append(">").append(opUpThruDay).append("</option>");
        writer.append("<option value=\"empty\"").append(("empty".equals(defaultOptionThru)? " selected": "")).append(">").append(opIsEmpty).append("</option>");
        writer.append("</select>");

        if (UtilValidate.isNotEmpty(modelFormField.getTitleStyle())) {
            writer.append("</span>");
        }

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderLookupField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.LookupField)
     */
    public void renderLookupField(Appendable writer, Map<String, Object> context, LookupField lookupField) throws IOException {
        ModelFormField modelFormField = lookupField.getModelFormField();

        writer.append("<input type=\"text\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        String value = modelFormField.getEntry(context, lookupField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(lookupField.getSize()));
        writer.append('"');

        Integer maxlength = lookupField.getMaxlength();
        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        String idName = modelFormField.getCurrentContainerId(context);
        if (UtilValidate.isNotEmpty(idName)) {
            writer.append(" id=\"");
            writer.append(idName);
            writer.append('"');
        }

        List<ModelForm.UpdateArea> updateAreas = modelFormField.getOnChangeUpdateAreas();
        boolean ajaxEnabled = updateAreas != null && this.javaScriptEnabled;
        if (!lookupField.getClientAutocompleteField() || ajaxEnabled) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        // add lookup pop-up button
        String descriptionFieldName = lookupField.getDescriptionFieldName();
        if (UtilValidate.isNotEmpty(descriptionFieldName)) {
            writer.append("<a href=\"javascript:call_fieldlookup3(document.");
            writer.append(modelFormField.getModelForm().getCurrentFormName(context));
            writer.append('.');
            writer.append(modelFormField.getParameterName(context));
            writer.append(",'");
            writer.append(descriptionFieldName);
            writer.append(",'");
        } else {
            writer.append("<a href=\"javascript:call_fieldlookup2(document.");
            writer.append(modelFormField.getModelForm().getCurrentFormName(context));
            writer.append('.');
            writer.append(modelFormField.getParameterName(context));
            writer.append(",'");
        }
        writer.append(appendExternalLoginKey(lookupField.getFormName(context)));
        writer.append("'");
        List<String> targetParameterList = lookupField.getTargetParameterList();
        for (String targetParameter: targetParameterList) {
            // named like: document.${formName}.${targetParameter}.value
            writer.append(", document.");
            writer.append(modelFormField.getModelForm().getCurrentFormName(context));
            writer.append(".");
            writer.append(targetParameter);
            writer.append(".value");
        }
        writer.append(");\">");
        writer.append("<img src=\"");
        this.appendContentUrl(writer, "/images/fieldlookup.gif");
        writer.append("\" width=\"15\" height=\"14\" border=\"0\" alt=\"Lookup\"/></a>");

        this.addAsterisks(writer, context, modelFormField);

        this.makeHyperlinkString(writer, lookupField.getSubHyperlink(), context);
        this.appendTooltip(writer, context, modelFormField);

        if (ajaxEnabled) {
            appendWhitespace(writer);
            writer.append("<script language=\"JavaScript\" type=\"text/javascript\">");
            appendWhitespace(writer);
            writer.append("ajaxAutoCompleter('").append(createAjaxParamsFromUpdateAreas(updateAreas, null, context)).append("');");
            appendWhitespace(writer);
            writer.append("</script>");
        }
        appendWhitespace(writer);

        //appendWhitespace(writer);
    }

    protected String appendExternalLoginKey(String target) {
        String result = target;
        String sessionId = ";jsessionid=" + request.getSession().getId();
        int questionIndex = target.indexOf("?");
        if (questionIndex == -1) {
            result += sessionId;
        } else {
            result = result.replace("?", sessionId + "?");
        }
        return result;
    }

    public void renderNextPrev(Appendable writer, Map<String, Object> context, ModelForm modelForm) throws IOException {
        boolean ajaxEnabled = false;
        List<ModelForm.UpdateArea> updateAreas = modelForm.getOnPaginateUpdateAreas();
        String targetService = modelForm.getPaginateTarget(context);
        if (this.javaScriptEnabled) {
            if (UtilValidate.isNotEmpty(updateAreas)) {
                ajaxEnabled = true;
            }
        }
        if (targetService == null) {
            targetService = "${targetService}";
        }
        if (UtilValidate.isEmpty(targetService) && updateAreas == null) {
            Debug.logWarning("Cannot paginate because TargetService is empty for the form: " + modelForm.getName(), module);
            return;
        }

        // get the parameterized pagination index and size fields
        int paginatorNumber = WidgetWorker.getPaginatorNumber(context);
        String viewIndexParam = modelForm.getMultiPaginateIndexField(context);
        String viewSizeParam = modelForm.getMultiPaginateSizeField(context);

        int viewIndex = modelForm.getViewIndex(context);
        int viewSize = modelForm.getViewSize(context);
        int listSize = modelForm.getListSize(context);

        int lowIndex = modelForm.getLowIndex(context);
        int highIndex = modelForm.getHighIndex(context);
        int actualPageSize = modelForm.getActualPageSize(context);

        // if this is all there seems to be (if listSize < 0, then size is unknown)
        if (actualPageSize >= listSize && listSize >= 0) return;

        // needed for the "Page" and "rows" labels
        Map<String, String> uiLabelMap = UtilGenerics.checkMap(context.get("uiLabelMap"));
        String pageLabel = "";
        String commonDisplaying = "";
        if (uiLabelMap == null) {
            Debug.logWarning("Could not find uiLabelMap in context", module);
        } else {
            pageLabel = uiLabelMap.get("CommonPage");
            Map<String, Integer> messageMap = UtilMisc.toMap("lowCount", Integer.valueOf(lowIndex + 1), "highCount", Integer.valueOf(lowIndex + actualPageSize), "total", Integer.valueOf(listSize));
            commonDisplaying = UtilProperties.getMessage("CommonUiLabels", "CommonDisplaying", messageMap, (Locale) context.get("locale"));
        }

        // for legacy support, the viewSizeParam is VIEW_SIZE and viewIndexParam is VIEW_INDEX when the fields are "viewSize" and "viewIndex"
        if (viewIndexParam.equals("viewIndex" + "_" + paginatorNumber)) viewIndexParam = "VIEW_INDEX" + "_" + paginatorNumber;
        if (viewSizeParam.equals("viewSize" + "_" + paginatorNumber)) viewSizeParam = "VIEW_SIZE" + "_" + paginatorNumber;

        String str = (String) context.get("_QBESTRING_");

        // strip legacy viewIndex/viewSize params from the query string
        String queryString = UtilHttp.stripViewParamsFromQueryString(str, "" + paginatorNumber);

        // strip parametrized index/size params from the query string
        HashSet<String> paramNames = new HashSet<String>();
        paramNames.add(viewIndexParam);
        paramNames.add(viewSizeParam);
        queryString = UtilHttp.stripNamedParamsFromQueryString(queryString, paramNames);

        String anchor = "";
        String paginateAnchor = modelForm.getPaginateTargetAnchor();
        if (paginateAnchor != null) anchor = "#" + paginateAnchor;

        // Create separate url path String and request parameters String,
        // add viewIndex/viewSize parameters to request parameter String
        String urlPath = UtilHttp.removeQueryStringFromTarget(targetService);
        StringBuilder prepLinkBuffer = new StringBuilder();
        String prepLinkQueryString = UtilHttp.getQueryStringFromTarget(targetService);
        if (prepLinkQueryString != null) {
            prepLinkBuffer.append(prepLinkQueryString);
        }
        if (prepLinkBuffer.indexOf("?") < 0) {
            prepLinkBuffer.append("?");
        } else if (prepLinkBuffer.indexOf("?", prepLinkBuffer.length() - 1) > 0) {
            prepLinkBuffer.append("&amp;");
        }
        if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) {
            prepLinkBuffer.append(queryString).append("&amp;");
        }
        prepLinkBuffer.append(viewSizeParam).append("=").append(viewSize).append("&amp;").append(viewIndexParam).append("=");
        String prepLinkText = prepLinkBuffer.toString();
        if (ajaxEnabled) {
            // Prepare params for prototype.js
            prepLinkText = prepLinkText.replace("?", "");
            prepLinkText = prepLinkText.replace("&amp;", "&");
        }

        writer.append("<div class=\"").append(modelForm.getPaginateStyle()).append("\">");
        appendWhitespace(writer);
        writer.append(" <ul>");
        appendWhitespace(writer);

        String linkText;

        // First button
        writer.append("  <li class=\"").append(modelForm.getPaginateFirstStyle());
        if (viewIndex > 0) {
            writer.append("\"><a href=\"");
            if (ajaxEnabled) {
                writer.append("javascript:ajaxUpdateAreas('").append(createAjaxParamsFromUpdateAreas(updateAreas, prepLinkText + 0 + anchor, context)).append("')");
            } else {
                linkText = prepLinkText + 0 + anchor;
                appendOfbizUrl(writer, urlPath + linkText);
            }
            writer.append("\">").append(modelForm.getPaginateFirstLabel(context)).append("</a>");
        } else {
            // disabled button
            writer.append("-disabled\">").append(modelForm.getPaginateFirstLabel(context));
        }
        writer.append("</li>");
        appendWhitespace(writer);

        // Previous button
        writer.append("  <li class=\"").append(modelForm.getPaginatePreviousStyle());
        if (viewIndex > 0) {
            writer.append("\"><a href=\"");
            if (ajaxEnabled) {
                writer.append("javascript:ajaxUpdateAreas('").append(createAjaxParamsFromUpdateAreas(updateAreas, prepLinkText + (viewIndex - 1) + anchor, context)).append("')");
            } else {
                linkText = prepLinkText + (viewIndex - 1) + anchor;
                appendOfbizUrl(writer, urlPath + linkText);
            }
            writer.append("\">").append(modelForm.getPaginatePreviousLabel(context)).append("</a>");
        } else {
            // disabled button
            writer.append("-disabled\">").append(modelForm.getPaginatePreviousLabel(context));
        }
        writer.append("</li>");
        appendWhitespace(writer);

        // Page select dropdown
        if (listSize > 0 && this.javaScriptEnabled) {
            writer.append("  <li>").append(pageLabel).append(" <select name=\"page\" size=\"1\" onchange=\"");
            if (ajaxEnabled) {
                writer.append("javascript:ajaxUpdateAreas('").append(createAjaxParamsFromUpdateAreas(updateAreas, prepLinkText + "' + this.value", context)).append(")");
            } else {
                linkText = prepLinkText;
                if (linkText.startsWith("/")) {
                    linkText = linkText.substring(1);
                }
                writer.append("location.href = '");
                appendOfbizUrl(writer, urlPath + linkText);
                writer.append("' + this.value;");
            }
            writer.append("\">");
            // actual value
            int page = 0;
            for (int i = 0; i < listSize;) {
                if (page == viewIndex) {
                    writer.append("<option selected value=\"");
                } else {
                    writer.append("<option value=\"");
                }
                writer.append(Integer.toString(page));
                writer.append("\">");
                writer.append(Integer.toString(1 + page));
                writer.append("</option>");
                // increment page and calculate next index
                page++;
                i = page * viewSize;
            }
            writer.append("</select></li>");
        }

        //  show row count
        writer.append("<li>");
        writer.append(commonDisplaying);
        writer.append("</li>");
        appendWhitespace(writer);

        // Next button
        writer.append("  <li class=\"").append(modelForm.getPaginateNextStyle());
        if (highIndex < listSize) {
            writer.append("\"><a href=\"");
            if (ajaxEnabled) {
                writer.append("javascript:ajaxUpdateAreas('").append(createAjaxParamsFromUpdateAreas(updateAreas, prepLinkText + (viewIndex + 1) + anchor, context)).append("')");
            } else {
                linkText = prepLinkText + (viewIndex + 1) + anchor;
                appendOfbizUrl(writer, urlPath + linkText);
            }
            writer.append("\">").append(modelForm.getPaginateNextLabel(context)).append("</a>");
        } else {
            // disabled button
            writer.append("-disabled\">").append(modelForm.getPaginateNextLabel(context));
        }
        writer.append("</li>");
        appendWhitespace(writer);

        // Last button
        writer.append("  <li class=\"").append(modelForm.getPaginateLastStyle());
        if (highIndex < listSize) {
            int lastIndex = UtilMisc.getViewLastIndex(listSize, viewSize);
            writer.append("\"><a href=\"");
            if (ajaxEnabled) {
                writer.append("javascript:ajaxUpdateAreas('").append(createAjaxParamsFromUpdateAreas(updateAreas, prepLinkText + lastIndex + anchor, context)).append("')");
            } else {
                linkText = prepLinkText + lastIndex + anchor;
                appendOfbizUrl(writer, urlPath + linkText);
            }
            writer.append("\">").append(modelForm.getPaginateLastLabel(context)).append("</a>");
        } else {
            // disabled button
            writer.append("-disabled\">").append(modelForm.getPaginateLastLabel(context));
        }
        writer.append("</li>");
        appendWhitespace(writer);

        writer.append(" </ul>");
        appendWhitespace(writer);
        writer.append("</div>");
        appendWhitespace(writer);
    }

    public void renderSortField(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, String titleText) throws IOException {
        boolean ajaxEnabled = false;
        ModelForm modelForm = modelFormField.getModelForm();
        List<ModelForm.UpdateArea> updateAreas = modelForm.getOnPaginateUpdateAreas();
        String targetService = modelForm.getPaginateTarget(context);
        if (this.javaScriptEnabled) {
            if (UtilValidate.isNotEmpty(updateAreas)) {
                ajaxEnabled = true;
            }
        }
        if (targetService == null) {
            targetService = "${targetService}";
        }
        if (UtilValidate.isEmpty(targetService) && updateAreas == null) {
            Debug.logWarning("Cannot sort because TargetService is empty for the form: " + modelForm.getName(), module);
            return;
        }

        String str = (String) context.get("_QBESTRING_");
        String oldSortField = modelForm.getSortField(context);
        String sortFieldStyle = modelFormField.getSortFieldStyle();

        // if the entry-name is defined use this instead of field name
        String columnField = modelFormField.getEntryName();
        if (UtilValidate.isEmpty(columnField)) {
            columnField = modelFormField.getFieldName();
        }

        // switch beetween asc/desc order
        String newSortField = columnField;
        if (UtilValidate.isNotEmpty(oldSortField)) {
            if (oldSortField.equals(columnField)) {
                newSortField = "-" + columnField;
                sortFieldStyle = modelFormField.getSortFieldStyleDesc();
            } else if (oldSortField.equals("-" + columnField)) {
                newSortField = columnField;
                sortFieldStyle = modelFormField.getSortFieldStyleAsc();
            }
        }

        //  strip sortField param from the query string
        HashSet<String> paramName = new HashSet<String>();
        paramName.add("sortField");
        String queryString = UtilHttp.stripNamedParamsFromQueryString(str, paramName);
        String urlPath = UtilHttp.removeQueryStringFromTarget(targetService);
        StringBuilder prepLinkBuffer = new StringBuilder();
        String prepLinkQueryString = UtilHttp.getQueryStringFromTarget(targetService);
        if (prepLinkQueryString != null) {
            prepLinkBuffer.append(prepLinkQueryString);
        }
        if (prepLinkBuffer.indexOf("?") < 0) {
            prepLinkBuffer.append("?");
        } else if (prepLinkBuffer.indexOf("?", prepLinkBuffer.length() - 1) > 0) {
            prepLinkBuffer.append("&amp;");
        }
        if (!UtilValidate.isEmpty(queryString) && !queryString.equals("null")) {
            prepLinkBuffer.append(queryString).append("&amp;");
        }
        prepLinkBuffer.append("sortField").append("=").append(newSortField);
        String prepLinkText = prepLinkBuffer.toString();
        if (ajaxEnabled) {
            prepLinkText = prepLinkText.replace("?", "");
            prepLinkText = prepLinkText.replace("&amp;", "&");
        }

        writer.append("<a");
        if (UtilValidate.isNotEmpty(sortFieldStyle)) {
            writer.append(" class=\"");
            writer.append(sortFieldStyle);
            writer.append("\"");
        }

        writer.append(" href=\"");
        if (ajaxEnabled) {
            writer.append("javascript:ajaxUpdateAreas('").append(createAjaxParamsFromUpdateAreas(updateAreas, prepLinkText, context)).append("')");
        } else {
            appendOfbizUrl(writer, urlPath + prepLinkText);
        }
        writer.append("\">").append(titleText).append("</a>");
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderFileField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.FileField)
     */
    public void renderFileField(Appendable writer, Map<String, Object> context, FileField textField) throws IOException {
        ModelFormField modelFormField = textField.getModelFormField();

        writer.append("<input type=\"file\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        String value = modelFormField.getEntry(context, textField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(textField.getSize()));
        writer.append('"');

        Integer maxlength = textField.getMaxlength();
        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        if (!textField.getClientAutocompleteField()) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        this.makeHyperlinkString(writer, textField.getSubHyperlink(), context);

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderPasswordField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.PasswordField)
     */
    public void renderPasswordField(Appendable writer, Map<String, Object> context, PasswordField passwordField) throws IOException {
        ModelFormField modelFormField = passwordField.getModelFormField();

        writer.append("<input type=\"password\"");

        appendClassNames(writer, context, modelFormField);

        writer.append(" name=\"");
        writer.append(modelFormField.getParameterName(context));
        writer.append('"');

        String value = modelFormField.getEntry(context, passwordField.getDefaultValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" value=\"");
            writer.append(value);
            writer.append('"');
        }

        writer.append(" size=\"");
        writer.append(Integer.toString(passwordField.getSize()));
        writer.append('"');

        Integer maxlength = passwordField.getMaxlength();
        if (maxlength != null) {
            writer.append(" maxlength=\"");
            writer.append(maxlength.toString());
            writer.append('"');
        }

        String idName = modelFormField.getCurrentContainerId(context);
        if (UtilValidate.isNotEmpty(idName)) {
            writer.append(" id=\"");
            writer.append(idName);
            writer.append('"');
        }

        if (!passwordField.getClientAutocompleteField()) {
            writer.append(" autocomplete=\"off\"");
        }

        writer.append("/>");

        this.addAsterisks(writer, context, modelFormField);

        this.makeHyperlinkString(writer, passwordField.getSubHyperlink(), context);

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    /* (non-Javadoc)
     * @see org.ofbiz.widget.form.FormStringRenderer#renderImageField(java.io.Writer, java.util.Map, org.ofbiz.widget.form.ModelFormField.ImageField)
     */
    public void renderImageField(Appendable writer, Map<String, Object> context, ImageField imageField) throws IOException {
        ModelFormField modelFormField = imageField.getModelFormField();

        writer.append("<img ");


        String value = modelFormField.getEntry(context, imageField.getValue(context));
        if (UtilValidate.isNotEmpty(value)) {
            writer.append(" src=\"");
            appendContentUrl(writer, value);
            writer.append('"');
        }

        writer.append(" border=\"");
        writer.append(Integer.toString(imageField.getBorder()));
        writer.append('"');

        Integer width = imageField.getWidth();
        if (width != null) {
            writer.append(" width=\"");
            writer.append(width.toString());
            writer.append('"');
        }

        Integer height = imageField.getHeight();
        if (height != null) {
            writer.append(" height=\"");
            writer.append(height.toString());
            writer.append('"');
        }

        String event = modelFormField.getEvent();
        String action = modelFormField.getAction(context);
        if (UtilValidate.isNotEmpty(event) && UtilValidate.isNotEmpty(action)) {
            writer.append(" ");
            writer.append(event);
            writer.append("=\"");
            writer.append(action);
            writer.append('"');
        }

        writer.append("/>");

        this.makeHyperlinkString(writer, imageField.getSubHyperlink(), context);

        this.appendTooltip(writer, context, modelFormField);

        //appendWhitespace(writer);
    }

    public void renderFieldGroupOpen(Appendable writer, Map<String, Object> context, ModelForm.FieldGroup fieldGroup) throws IOException {
        String style = fieldGroup.getStyle();
        String id = fieldGroup.getId();
        FlexibleStringExpander titleNotExpanded = FlexibleStringExpander.getInstance(fieldGroup.getTitle());
        String title = titleNotExpanded.expandString(context);
        Boolean collapsed = fieldGroup.initiallyCollapsed();
        String collapsibleAreaId = fieldGroup.getId() + "_body";

        if (UtilValidate.isNotEmpty(style) || UtilValidate.isNotEmpty(id) || UtilValidate.isNotEmpty(title)) {

            writer.append("<div class=\"fieldgroup");
            if (UtilValidate.isNotEmpty(style)) {
                writer.append(" ");
                writer.append(style);
            }
            writer.append("\"");
            if (UtilValidate.isNotEmpty(id)) {
                writer.append(" id=\"");
                writer.append(id);
                writer.append("\"");
            }
            writer.append(">");

            writer.append("<div class=\"fieldgroup-title-bar\"><table><tr><td class=\"collapse\">");

            if (fieldGroup.collapsible()) {
                String expandToolTip = null;
                String collapseToolTip = null;
                Map<String, Object> uiLabelMap = UtilGenerics.checkMap(context.get("uiLabelMap"));
                //Map<String, Object> paramMap = UtilGenerics.checkMap(context.get("requestParameters"));
                if (uiLabelMap != null) {
                    expandToolTip = (String) uiLabelMap.get("CommonExpand");
                    collapseToolTip = (String) uiLabelMap.get("CommonCollapse");
                }

                writer.append("<ul><li class=\"");
                if (collapsed) {
                    writer.append("collapsed\"><a ");
                    writer.append("onclick=\"javascript:toggleCollapsiblePanel(this, '").append(collapsibleAreaId).append("', '").append(expandToolTip).append("', '").append(collapseToolTip).append("');\"");
                } else {
                    writer.append("expanded\"><a ");
                    writer.append("onclick=\"javascript:toggleCollapsiblePanel(this, '").append(collapsibleAreaId).append("', '").append(expandToolTip).append("', '").append(collapseToolTip).append("');\"");
                }
                writer.append(">&nbsp&nbsp&nbsp</a></li></ul>");

                appendWhitespace(writer);
            }
            writer.append("</td><td>");

            if (UtilValidate.isNotEmpty(title)) {
                writer.append("<div class=\"title\">");
                writer.append(title);
                writer.append("</div>");
            }

            writer.append("</td></tr></table></div>");

            writer.append("<div id=\"").append(collapsibleAreaId).append("\" class=\"fieldgroup-body\"");
            if (fieldGroup.collapsible() && collapsed) {
                writer.append(" style=\"display: none;\"");
            }
            writer.append(">");
        }
    }

    public void renderFieldGroupClose(Appendable writer, Map<String, Object> context, ModelForm.FieldGroup fieldGroup) throws IOException {
        String style = fieldGroup.getStyle();
        String id = fieldGroup.getId();
        String title = fieldGroup.getTitle();
        if (UtilValidate.isNotEmpty(style) || UtilValidate.isNotEmpty(id) || UtilValidate.isNotEmpty(title)) {
            writer.append("</div>");
            writer.append("</div>");
        }
    }

    // TODO: Remove embedded styling
    public void renderBanner(Appendable writer, Map<String, Object> context, ModelForm.Banner banner) throws IOException {
        writer.append(" <table width=\"100%\">  <tr>");
        String style = banner.getStyle(context);
        String leftStyle = banner.getLeftTextStyle(context);
        if (UtilValidate.isEmpty(leftStyle)) leftStyle = style;
        String rightStyle = banner.getRightTextStyle(context);
        if (UtilValidate.isEmpty(rightStyle)) rightStyle = style;

        String leftText = banner.getLeftText(context);
        if (UtilValidate.isNotEmpty(leftText)) {
            writer.append("   <td align=\"left\">");
            if (UtilValidate.isNotEmpty(leftStyle)) {
               writer.append("<div");
               writer.append(" class=\"");
               writer.append(leftStyle);
               writer.append("\"");
               writer.append(">");
            }
            writer.append(leftText);
            if (UtilValidate.isNotEmpty(leftStyle)) {
                writer.append("</div>");
            }
            writer.append("</td>");
        }

        String text = banner.getText(context);
        if (UtilValidate.isNotEmpty(text)) {
            writer.append("   <td align=\"center\">");
            if (UtilValidate.isNotEmpty(style)) {
               writer.append("<div");
               writer.append(" class=\"");
               writer.append(style);
               writer.append("\"");
               writer.append(">");
            }
            writer.append(text);
            if (UtilValidate.isNotEmpty(style)) {
                writer.append("</div>");
            }
            writer.append("</td>");
        }

        String rightText = banner.getRightText(context);
        if (UtilValidate.isNotEmpty(rightText)) {
            writer.append("   <td align=\"right\">");
            if (UtilValidate.isNotEmpty(rightStyle)) {
               writer.append("<div");
               writer.append(" class=\"");
               writer.append(rightStyle);
               writer.append("\"");
               writer.append(">");
            }
            writer.append(rightText);
            if (UtilValidate.isNotEmpty(rightStyle)) {
                writer.append("</div>");
            }
            writer.append("</td>");
        }
        writer.append("</tr> </table>");
    }

    /**
     * Renders a link for the column header fields when there is a header-link="" specified in the <field > tag, using
     * style from header-link-style="".  Also renders a selectAll checkbox in multi forms.
     * @param writer
     * @param context
     * @param modelFormField
     * @param titleText
     */
    public void renderHyperlinkTitle(Appendable writer, Map<String, Object> context, ModelFormField modelFormField, String titleText) throws IOException {
        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 = HyperlinkField.DEFAULT_TARGET_TYPE;
            if (UtilValidate.isNotEmpty(targetBuffer.toString()) && targetBuffer.toString().toLowerCase().startsWith("javascript:")) {
                targetType="plain";
            }
            WidgetWorker.makeHyperlinkString(writer, modelFormField.getHeaderLinkStyle(), targetType, targetBuffer.toString(), null, titleText, null, modelFormField, this.request, this.response, null, null);
        } else if (modelFormField.isSortField()) {
            renderSortField (writer, context, modelFormField, titleText);
        } else if (modelFormField.isRowSubmit()) {
            if (UtilValidate.isNotEmpty(titleText)) writer.append(titleText).append("<br/>");
            writer.append("<input type=\"checkbox\" name=\"selectAll\" value=\"Y\" onclick=\"javascript:toggleAll(this, '");
            writer.append(modelFormField.getModelForm().getName());
            writer.append("');\"/>");
        } else {
             writer.append(titleText);
        }
    }

    public void renderContainerFindField(Appendable writer, Map<String, Object> context, ContainerField containerField) throws IOException {
        writer.append("<div ");
        String id = containerField.getModelFormField().getIdName();
        if (UtilValidate.isNotEmpty(id)) {
            writer.append("id=\"");
            writer.append(id);
            writer.append("\" ");
        }
        String className = containerField.getModelFormField().getWidgetStyle();
        if (UtilValidate.isNotEmpty(className)) {
            writer.append("class=\"");
            writer.append(className);
            writer.append("\" ");
        }
        writer.append("/>");
    }

    /** Create an ajaxXxxx JavaScript CSV string from a list of UpdateArea objects. See
     * <code>selectall.js</code>.
     * @param updateAreas
     * @param extraParams Renderer-supplied additional target parameters
     * @param context
     * @return Parameter string or empty string if no UpdateArea objects were found
     */
    public String createAjaxParamsFromUpdateAreas(List<ModelForm.UpdateArea> updateAreas, String extraParams, Map<String, ? extends Object> context) {
        if (updateAreas == null) {
            return "";
        }
        StringBuilder ajaxUrl = new StringBuilder();
        boolean firstLoop = true;
        for (ModelForm.UpdateArea updateArea : updateAreas) {
            if (firstLoop) {
                firstLoop = false;
            } else {
                ajaxUrl.append(",");
            }
            String targetUrl = updateArea.getAreaTarget(context);
            String ajaxParams = getAjaxParamsFromTarget(targetUrl);
            if (UtilValidate.isNotEmpty(extraParams)) {
                if (ajaxParams.length() > 0 && !extraParams.startsWith("&")) {
                    ajaxParams += "&";
                }
                ajaxParams += extraParams;
            }
            ajaxUrl.append(updateArea.getAreaId()).append(",");
            try {
                appendOfbizUrl(ajaxUrl, UtilHttp.removeQueryStringFromTarget(targetUrl));
            } catch (IOException e) {
                throw UtilMisc.initCause(new InternalError(e.getMessage()), e);
            }
            ajaxUrl.append(",").append(ajaxParams);
        }
        return ajaxUrl.toString();
    }
}
TOP

Related Classes of org.ofbiz.widget.html.HtmlFormRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.