/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.taglibs;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
import nl.strohalm.cyclos.entities.customization.fields.CustomField;
import nl.strohalm.cyclos.entities.customization.fields.CustomField.Type;
import nl.strohalm.cyclos.entities.customization.fields.CustomFieldPossibleValue;
import nl.strohalm.cyclos.entities.customization.fields.CustomFieldValue;
import nl.strohalm.cyclos.entities.customization.fields.Validation;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.entities.settings.LocalSettings.MemberResultDisplay;
import nl.strohalm.cyclos.services.settings.SettingsService;
import nl.strohalm.cyclos.utils.MessageHelper;
import nl.strohalm.cyclos.utils.RangeConstraint;
import nl.strohalm.cyclos.utils.SpringHelper;
import nl.strohalm.cyclos.utils.StringHelper;
import nl.strohalm.cyclos.utils.conversion.IdConverter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
/**
* Tag used to render a custom field
* @author luis
*/
public class CustomFieldTag extends TagSupport {
private static final long serialVersionUID = 1356009486707156305L;
private boolean editable = true;
private boolean enabled = true;
private CustomField field;
private String fieldName;
private String styleId;
private boolean search;
private boolean textOnly;
private String size;
private Object value;
private String valueName;
private Collection<? extends CustomFieldValue> collection;
private boolean encodeHtml = true;
private MessageHelper messageHelper;
private SettingsService settingsService;
@Override
public int doEndTag() throws JspException {
try {
if (field == null) {
throw new JspException("Field is null on CustomFieldTag");
}
// Get the field value from collection if needed
if (value == null && collection != null) {
for (final CustomFieldValue customValue : collection) {
if (field.equals(customValue.getField())) {
value = customValue;
break;
}
}
}
final StringBuilder sb = new StringBuilder();
// There is a hidden that will store the field id
if (StringUtils.isNotEmpty(fieldName)) {
sb.append("<input type=\"hidden\" name=\"").append(fieldName).append("\" value=\"").append(field.getId()).append("\">");
}
final CustomField.Control control = field.getControl();
if (editable && !textOnly) {
if (field.getType() == CustomField.Type.BOOLEAN) {
if (search) {
// When a boolean is on search, we use a select with true and false values
renderSelect(sb);
} else {
// Boolean is always a check box. As it is not submitted when is not checked, we must use a hidden that will be submitted
renderCheckBox(sb);
}
} else if (field.getType() == Type.MEMBER) {
renderMemberSelect(sb);
} else if (field.getType() == CustomField.Type.ENUMERATED) {
final Collection<CustomFieldPossibleValue> possibleValues = field.getPossibleValues(false);
if (CollectionUtils.isEmpty(possibleValues)) {
// If there are no possible values, render a hidden, so it is ensured that a value will be submitted
sb.append("<input type=\"hidden\" name=\"").append(valueName).append("\">");
} else {
if (control == CustomField.Control.RADIO && !search) {
// Render a radio group
renderRadioGroup(sb);
} else {
// Render a select box
renderSelect(sb);
}
}
} else if (!search && field.getControl() == CustomField.Control.TEXTAREA) {
renderTextarea(sb);
} else if (!search && field.getControl() == CustomField.Control.RICH_EDITOR) {
renderRichEditor(sb);
} else {
renderText(sb);
}
} else {
renderDisplay(sb);
}
pageContext.getOut().write(sb.toString());
} catch (final IOException e) {
throw new JspException(e);
} finally {
release();
}
return EVAL_PAGE;
}
public Collection<? extends CustomFieldValue> getCollection() {
return collection;
}
public CustomField getField() {
return field;
}
public String getFieldName() {
return fieldName;
}
public String getSize() {
return size;
}
public String getStyleId() {
return styleId;
}
public Object getValue() {
return value;
}
public String getValueName() {
return valueName;
}
public boolean isEditable() {
return editable;
}
public boolean isEnabled() {
return enabled;
}
public boolean isEncodeHtml() {
return encodeHtml;
}
public boolean isSearch() {
return search;
}
public boolean isTextOnly() {
return textOnly;
}
@Override
public void release() {
super.release();
field = null;
fieldName = null;
valueName = null;
value = null;
collection = null;
enabled = true;
editable = true;
search = false;
textOnly = false;
encodeHtml = true;
size = null;
styleId = null;
}
public void setCollection(final Collection<? extends CustomFieldValue> collection) {
this.collection = collection;
}
public void setEditable(final boolean editable) {
this.editable = editable;
}
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public void setEncodeHtml(final boolean encodeHtml) {
this.encodeHtml = encodeHtml;
}
public void setField(final CustomField field) {
this.field = field;
}
public void setFieldName(final String name) {
fieldName = name;
}
@Override
public void setPageContext(final PageContext pageContext) {
super.setPageContext(pageContext);
messageHelper = SpringHelper.bean(pageContext.getServletContext(), MessageHelper.class);
settingsService = SpringHelper.bean(pageContext.getServletContext(), SettingsService.class);
}
public void setSearch(final boolean search) {
this.search = search;
}
public void setSize(final String size) {
this.size = size;
}
public void setStyleId(final String styleId) {
this.styleId = styleId;
}
public void setTextOnly(final boolean textOnly) {
this.textOnly = textOnly;
}
public void setValue(final Object value) {
this.value = value;
}
public void setValueName(final String valueField) {
valueName = valueField;
}
private String ensureHtml(final String string) {
return StringUtils.replace(StringEscapeUtils.escapeHtml(string), "\n", "<br>");
}
private Member getMemberValue() {
if (value instanceof CustomFieldValue) {
return ((CustomFieldValue) value).getMemberValue();
}
return null;
}
private CustomFieldPossibleValue getPossibleValue() {
if (value instanceof CustomFieldValue) {
return ((CustomFieldValue) value).getPossibleValue();
}
return null;
}
/**
* Return a style class for the current field size
*/
private String getSizeClass() {
if (StringUtils.isNotEmpty(size)) {
return size;
}
final CustomField.Size size = field == null ? null : field.getSize();
if (size == null || size == CustomField.Size.DEFAULT) {
return "";
}
return size.name().toLowerCase();
}
private String getStringValue() {
String string;
if (value instanceof String) {
string = (String) value;
} else if (value instanceof CustomFieldValue) {
string = ((CustomFieldValue) value).getValue();
} else {
string = null;
}
if (StringUtils.isNotEmpty(field.getPattern())) {
string = StringHelper.applyMask(field.getPattern(), string);
}
return string == null ? "" : string;
}
/**
* Returns a collection containing all possible values which are not disabled, however, keeping the current value even when disabled
*/
private Collection<CustomFieldPossibleValue> removeDisabledValues(final CustomFieldPossibleValue selected, final Collection<CustomFieldPossibleValue> possibleValues) {
final Collection<CustomFieldPossibleValue> result = new ArrayList<CustomFieldPossibleValue>();
for (final CustomFieldPossibleValue possibleValue : possibleValues) {
boolean useField = true;
if (!possibleValue.isEnabled()) {
if (selected == null || !selected.equals(possibleValue)) {
useField = false;
}
}
if (useField) {
result.add(possibleValue);
}
}
return result;
}
private void renderCheckBox(final StringBuilder sb) throws JspException {
final boolean value = Boolean.parseBoolean(getStringValue());
sb.append("<input type=\"hidden\" id=\"_value_of_").append(field.getId()).append("\" name=\"").append(valueName).append("\" value=\"").append(value).append("\">");
sb.append("<input type=\"checkbox\" id=\"_check_of_").append(field.getId()).append("\" class=\"checkbox\" onclick=\"if (!this.disabled){$('_value_of_").append(field.getId()).append("').value=String(this.checked);}\"");
if (!enabled) {
sb.append("disabled ");
}
if (value) {
sb.append(" checked");
}
sb.append(">");
}
private void renderDisplay(final StringBuilder sb) throws JspException {
boolean skipEncode = false;
String value;
switch (field.getType()) {
case ENUMERATED:
try {
value = getPossibleValue().getValue();
} catch (final NullPointerException e) {
value = "";
}
break;
case BOOLEAN:
final String key = "true".equals(getStringValue()) ? "global.yes" : "global.no";
value = messageHelper.message(key);
break;
case URL:
value = getStringValue();
if (StringUtils.isNotEmpty(value)) {
if (!value.contains("://")) {
value = "http://" + value;
}
if (editable) {
value = "<a href=\"" + value + "\" class=\"default\" target=\"_blank\">" + value + "</a>";
skipEncode = true;
}
}
break;
case MEMBER:
final Member member = getMemberValue();
if (member == null) {
value = null;
} else {
if (editable) {
// Editable - render a profile link
final StringWriter sw = new StringWriter();
pageContext.pushBody(sw);
final ProfileTag profileTag = new ProfileTag();
profileTag.setPageContext(pageContext);
profileTag.setElementId(member.getId());
profileTag.doStartTag();
profileTag.doEndTag();
pageContext.popBody();
value = sw.toString();
skipEncode = true;
} else {
// Just print out the member username or name, according to the settings
final MemberResultDisplay memberResultDisplay = settingsService.getLocalSettings().getMemberResultDisplay();
if (memberResultDisplay == MemberResultDisplay.USERNAME) {
value = member.getUsername();
} else {
value = member.getName();
}
}
}
break;
default:
value = getStringValue();
break;
}
if (!textOnly) {
sb.append("<input type=\"text\" name=\"").append(valueName).append("\" value=\"");
}
value = StringUtils.trimToEmpty(value);
String script = null;
if (!skipEncode && encodeHtml && field.getControl() != CustomField.Control.RICH_EDITOR) {
value = StringUtils.replace(StringUtils.replace(StringUtils.replace(StringUtils.replace(value, "\"", """), "<", "<"), ">", ">"), "\n", "<br>");
} else if (field.getControl() == CustomField.Control.RICH_EDITOR) {
Integer lastRichTextSeq = (Integer) pageContext.getRequest().getAttribute("lastRichTextSeq");
if (lastRichTextSeq == null) {
lastRichTextSeq = 0;
}
lastRichTextSeq++;
pageContext.getRequest().setAttribute("lastRichTextSeq", lastRichTextSeq);
final String containerId = "valueContainer_" + lastRichTextSeq;
value = "<div id='" + containerId + "' style='display:none;overflow:auto'>" + value + "</div>";
script = "<script>\nEvent.observe(self, 'load', function() {\n" +
" var " + containerId + " = $('" + containerId + "');\n" +
containerId + ".style.width = $(" + containerId + ".parentElement).getDimensions().width + 'px';\n" +
containerId + ".show();\n" +
"});\n</script>\n";
}
sb.append(value);
if (!textOnly) {
sb.append("\" class=\"" + getSizeClass() + " readonly InputBoxDisabled\" readonly>\n");
}
if (script != null) {
sb.append(script);
}
}
private void renderMemberSelect(final StringBuilder sb) {
final Member memberValue = getMemberValue();
final String idFieldId = "memberId_field_" + field.getId();
final String usernameFieldId = "memberUsername_field_" + field.getId();
final String usernameDivId = "membersByUsername_field_" + field.getId();
final String nameFieldId = "memberName_field_" + field.getId();
final String nameDivId = "membersByName_field_" + field.getId();
final boolean requiredField = field != null && field.getValidation().isRequired();
final String className = enabled ? "InputBoxEnabled" : "InputBoxDisabled";
sb.append("<table class='nested' width='100%'>\n");
sb.append(" <tr>\n");
sb.append(" <td class='label' width='25%'>").append(messageHelper.message("member.username")).append("</td>\n");
sb.append(" <td>\n");
sb.append(" <input type='hidden' id='").append(idFieldId).append("' name='").append(valueName).append("' value='").append(memberValue == null ? "" : memberValue.getId()).append("'>\n");
sb.append(" <input id='").append(usernameFieldId).append("' class='full ").append(className).append("' ").append(enabled ? "" : "disabled='disabled'").append(" value='").append(memberValue == null ? "" : StringEscapeUtils.escapeHtml(memberValue.getUsername())).append("'>\n");
sb.append(" <div id='").append(usernameDivId).append("' class='autoComplete'>\n");
sb.append(" </td>\n");
if (requiredField) {
sb.append("<td rowspan='2' width='10px' style='vertical-align:top'> <span class='fieldDecoration' style='vertical-align:top'>*</span>");
}
sb.append(" </tr>\n");
sb.append(" <tr>\n");
sb.append(" <td class='label'>").append(messageHelper.message("member.name")).append("</td>\n");
sb.append(" <td>\n");
sb.append(" <input id='").append(nameFieldId).append("' class='full ").append(className).append("' ").append(enabled ? "" : "disabled='disabled'").append(" value='").append(memberValue == null ? "" : StringEscapeUtils.escapeHtml(memberValue.getName())).append("'>\n");
sb.append(" <div id='").append(nameDivId).append("' class='autoComplete'>\n");
sb.append(" </td>\n");
sb.append(" </tr>\n");
sb.append("</table>\n");
sb.append("<script>\n");
sb.append("prepareForMemberAutocomplete('")
.append(usernameFieldId).append("','")
.append(usernameDivId).append("',")
.append("{paramName:'username'},'")
.append(idFieldId).append("','")
.append(usernameFieldId).append("','")
.append(nameFieldId).append("');\n");
sb.append("prepareForMemberAutocomplete('")
.append(nameFieldId).append("','")
.append(nameDivId).append("',")
.append("{paramName:'name'},'")
.append(idFieldId).append("','")
.append(usernameFieldId).append("','")
.append(nameFieldId).append("');\n");
sb.append("</script>\n");
}
private void renderRadioGroup(final StringBuilder sb) throws JspException {
final CustomFieldPossibleValue value = getPossibleValue();
sb.append("<table border='0' cellpadding='0' cellspacing='0' style='border-spacing:0px;'>\n");
final boolean requiredField = field != null && field.getValidation().isRequired();
sb.append("<tr>\n");
int i = 0;
int controlsPerRow = Integer.MAX_VALUE;
if (field != null && field.getSize() != null) {
switch (field.getSize()) {
case TINY:
controlsPerRow = 1;
break;
case SMALL:
controlsPerRow = 2;
break;
case MEDIUM:
controlsPerRow = 3;
break;
case LARGE:
controlsPerRow = 4;
break;
}
}
String selectedValue = "";
final String name = "_radio_" + field.getId();
// Remove the disabled possible values, but keep the current value even if it's disabled
final Collection<CustomFieldPossibleValue> possibleValues = removeDisabledValues(value, field.getPossibleValues(false));
// Check whether the default value will be used
boolean useDefault = !isSearch() && this.value == null;
if (this.value instanceof CustomFieldValue) {
// Use on new values only
final CustomFieldValue fieldValue = (CustomFieldValue) this.value;
useDefault = fieldValue.isTransient();
}
// Render each radio
for (final CustomFieldPossibleValue possibleValue : possibleValues) {
final String id = name + "_" + i;
final String idAsString = String.valueOf(possibleValue.getId());
final boolean checked = ObjectUtils.equals(value, possibleValue) || (useDefault && possibleValue.isDefaultValue());
if (checked) {
selectedValue = idAsString;
}
sb.append("<td valign='top'><input type='radio' name='").append(name).append("' id=\"").append(id).append("\" class='radio' value='").append(idAsString).append("'").append(enabled ? "" : " disabled").append(checked ? " checked" : "");
sb.append(" onclick=\"if (!this.disabled){$('_value_of_").append(field.getId()).append("').value=this.value;}\"");
sb.append("></td>\n");
final boolean isRequired = requiredField && i == possibleValues.size() - 1;
sb.append("<td style='padding-right:5px'><label ");
if (isRequired) {
sb.append("class=\"required\" ");
}
sb.append(" for=\"").append(id).append("\">").append(possibleValue.getValue()).append("</label></td>\n");
i++;
if (i % controlsPerRow == 0) {
sb.append("<tr>\n</tr>\n");
}
}
sb.append("</tr>\n");
sb.append("</table>\n");
sb.append("<input type=\"hidden\" id=\"_value_of_").append(field.getId()).append("\" name=\"").append(valueName).append("\" value=\"" + selectedValue + "\">\n");
}
private void renderRichEditor(final StringBuilder sb) {
final RichTextAreaTag tag = new RichTextAreaTag();
tag.setStyleId("richText" + getField().getId());
tag.setDisabled(!enabled);
tag.setName(valueName);
tag.setPageContext(pageContext);
tag.setValue(getStringValue());
try {
tag.doStartTag();
tag.doEndTag();
} catch (final JspException e) {
throw new RuntimeException(e);
}
}
private void renderSelect(final StringBuilder sb) throws JspException {
final boolean hasChildren = CollectionUtils.isNotEmpty(field.getChildren());
final boolean hasParent = field.getParent() != null;
// We show the empty label in 2 situations: search or required fields
String emptyLabel = "";
if (search || field.getValidation().isRequired()) {
if (search) {
emptyLabel = StringUtils.trimToEmpty(field.getAllSelectedLabel());
if (StringUtils.isEmpty(emptyLabel)) {
emptyLabel = messageHelper.message("global.search.all");
}
} else {
emptyLabel = messageHelper.message("global.select.empty");
}
}
final CustomFieldPossibleValue selected = getPossibleValue();
final Collection<CustomFieldPossibleValue> possibleValues = removeDisabledValues(selected, field.getPossibleValues(false));
// We will render a MultiDropDown control if we are on search for enumerated fields, and the field has no relationships
if (!hasChildren && !hasParent && search && field.getType() == CustomField.Type.ENUMERATED && field.getPossibleValues(false).size() > 2) {
// MultiDropDown
final StringWriter temp = new StringWriter();
pageContext.pushBody(temp);
final MultiDropDownTag multiSelect = new MultiDropDownTag();
multiSelect.setPageContext(pageContext);
multiSelect.setName(valueName);
multiSelect.setSingleField(true);
multiSelect.doStartTag();
multiSelect.setEmptyLabel(emptyLabel);
final OptionTag option = new OptionTag();
final List<String> values = Arrays.asList(StringUtils.trimToEmpty(getStringValue()).split(","));
for (final CustomFieldPossibleValue possibleValue : possibleValues) {
final String idAsString = String.valueOf(possibleValue.getId());
option.setParent(multiSelect);
option.setPageContext(pageContext);
option.setValue(idAsString);
option.setText(possibleValue.getValue());
option.setSelected(values.contains(idAsString));
option.doStartTag();
option.doEndTag();
}
multiSelect.doEndTag();
pageContext.popBody();
sb.append(temp.toString());
} else {
// Normal select or search for booleans
final String id = "custom_field_select_" + field.getId();
sb.append("<select id=\"").append(id).append("\"");
sb.append(" fieldId=\"").append(field.getId()).append("\"");
sb.append(" fieldName=\"").append(field.getInternalName()).append("\" name=\"").append(valueName).append('"');
if (search) {
sb.append(" fieldEmptyLabel=\"").append(StringEscapeUtils.escapeHtml(emptyLabel)).append('"');
}
final Validation validation = field.getValidation();
final List<String> classes = new ArrayList<String>();
if (validation != null && validation.isRequired() && !search) {
classes.add("required");
}
if (!enabled) {
classes.add("InputBoxDisabled");
sb.append(" disabled");
}
sb.append(" class=\"").append(StringUtils.join(classes.iterator(), ' ')).append("\">\n");
sb.append("<option value=''>");
sb.append(StringEscapeUtils.escapeHtml(emptyLabel));
sb.append("</option>\n");
Long initialOptionId = null;
if (field.getType() == CustomField.Type.ENUMERATED) {
// Render each possible value as an enumerated value
CustomFieldPossibleValue value = selected;
// When the value is not a PossibleValue, try to find it as String
if (value == null) {
final String valueAsString = getStringValue();
if (StringUtils.isNotEmpty(valueAsString)) {
// The value as string is the possible value id
final Long possibleValueId = IdConverter.instance().valueOf(valueAsString);
value = (CustomFieldPossibleValue) CollectionUtils.find(field.getPossibleValues(false), new Predicate() {
@Override
public boolean evaluate(final Object obj) {
final CustomFieldPossibleValue pv = (CustomFieldPossibleValue) obj;
return pv.getId().equals(possibleValueId);
}
});
}
}
// As child fields have their options loaded via AJAX, the form.reset() method doesn't return it to the initial state.
// Store the options
if (value != null && field.getParent() != null) {
initialOptionId = value.getId();
}
// Check whether the default value will be used
boolean useDefault = false;
if (!isSearch()) {
if (this.value == null) {
useDefault = true;
} else if (this.value instanceof CustomFieldValue) {
// Use on new values only
final CustomFieldValue fieldValue = (CustomFieldValue) this.value;
useDefault = fieldValue.isTransient();
}
}
// When a field has children, store it's current value on the page scope, so that child fields can filter their possible values
if (hasChildren) {
pageContext.setAttribute("valueForField_" + field.getId(), value);
}
// Write the options
for (final CustomFieldPossibleValue possibleValue : possibleValues) {
final String idAsString = String.valueOf(possibleValue.getId());
sb.append("<option");
if (ObjectUtils.equals(value, possibleValue) || (useDefault && possibleValue.isDefaultValue())) {
sb.append(" selected");
}
sb.append(" value=\"").append(idAsString).append("\">");
sb.append(ensureHtml(possibleValue.getValue())).append("</option>\n");
}
} else {
// Render the options for a boolean
sb.append("<option value='true'");
if (value != null && "true".equalsIgnoreCase(value.toString())) {
sb.append(" selected");
}
sb.append(">").append(messageHelper.message("global.yes")).append("</option>\n");
sb.append("<option value='false'");
if (value != null && "false".equalsIgnoreCase(value.toString())) {
sb.append(" selected");
}
sb.append(">").append(messageHelper.message("global.no")).append("</option>\n");
}
sb.append("</select>\n");
if (hasChildren) {
sb.append("<script>\n");
sb.append("$('").append(id).append("').onchange = function() {\n");
for (final CustomField child : field.getChildren()) {
final String childId = "custom_field_select_" + child.getId();
sb.append("updateCustomFieldChildValues('").append(field.getNature()).append("', '").append(id).append("', '").append(childId).append("');\n");
}
sb.append("");
sb.append("}\n");
sb.append("Event.observe(self, 'loadi', $('").append(id).append("').onchange);\n");
sb.append("</script>\n");
}
if (field.getParent() != null) {
sb.append("<script>\n");
if (initialOptionId != null) {
// Write the initial value id, so the form.reset will work
sb.append("$('").append(id).append("').initialOptionId = \"").append(initialOptionId).append("\";\n");
}
// Write the initial options, so they will be correct on form.reset
sb.append("$('").append(id).append("').initialOptions = [");
boolean first = true;
for (final CustomFieldPossibleValue possibleValue : possibleValues) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append("new Option(\"").append(StringEscapeUtils.escapeJavaScript(possibleValue.getValue())).append("\",\"").append(possibleValue.getId()).append("\")");
}
sb.append("];\n");
sb.append("</script>\n");
}
}
}
private void renderText(final StringBuilder sb) throws JspException {
final List<String> classNames = new ArrayList<String>();
final Validation validation = field.getValidation();
if (validation != null && validation.isRequired() && !search) {
classNames.add("required");
}
final String pattern = StringUtils.trimToNull(field.getPattern());
switch (field.getType()) {
case DATE:
classNames.add("date");
break;
case INTEGER:
classNames.add("number");
break;
case DECIMAL:
classNames.add("float");
break;
case STRING:
if (pattern != null) {
classNames.add("pattern");
}
break;
}
final String sizeClass = getSizeClass();
if (StringUtils.isNotEmpty(sizeClass)) {
classNames.add(sizeClass);
}
final String value = getStringValue();
sb.append("<input type=\"text\" fieldName=\"").append(field.getInternalName()).append("\" name=\"").append(valueName).append("\" value=\"").append(StringEscapeUtils.escapeHtml(value)).append('"');
if (enabled) {
classNames.add("InputBoxEnabled");
} else {
sb.append(" readonly");
classNames.add("InputBoxDisabled");
}
if (StringUtils.isNotEmpty(styleId)) {
sb.append(" id=\"").append(styleId).append('"');
}
if (pattern != null) {
sb.append(" maskPattern=\"").append(StringEscapeUtils.escapeHtml(pattern)).append('"');
}
final RangeConstraint lengthConstraint = validation == null ? null : validation.getLengthConstraint();
if (lengthConstraint != null && lengthConstraint.getMax() != null && lengthConstraint.getMax() > 0) {
sb.append(" maxLength=\"").append(lengthConstraint.getMax()).append('"');
}
sb.append(" class=\"").append(StringUtils.join(classNames.iterator(), ' ')).append("\">\n");
}
private void renderTextarea(final StringBuilder sb) {
final List<String> classNames = new ArrayList<String>();
final Validation validation = field.getValidation();
if (validation != null && validation.isRequired() && !search) {
classNames.add("required");
}
sb.append("<textarea rows='5' fieldId='").append(field.getId()).append("' fieldName=\"").append(field.getInternalName()).append("\" name=\"").append(valueName).append('"');
final RangeConstraint lengthConstraint = validation == null ? null : validation.getLengthConstraint();
if (lengthConstraint != null && lengthConstraint.getMax() != null && lengthConstraint.getMax() > 0) {
sb.append(" maxLength=\"").append(lengthConstraint.getMax()).append('"');
classNames.add("maxLength");
}
if (enabled) {
classNames.add("InputBoxEnabled");
} else {
classNames.add("InputBoxDisabled");
sb.append(" readonly");
}
final String sizeClass = getSizeClass();
if (StringUtils.isNotEmpty(sizeClass)) {
classNames.add(sizeClass);
}
sb.append(" class=\"").append(StringUtils.join(classNames.iterator(), ' ')).append("\">").append(getStringValue()).append("</textarea>");
}
}