1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.internal.renderkit.renderer;
21
22 import org.apache.myfaces.tobago.config.TobagoConfig;
23 import org.apache.myfaces.tobago.context.Markup;
24 import org.apache.myfaces.tobago.internal.component.AbstractUITextarea;
25 import org.apache.myfaces.tobago.internal.util.AccessKeyLogger;
26 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
27 import org.apache.myfaces.tobago.internal.util.RenderUtils;
28 import org.apache.myfaces.tobago.internal.util.StringUtils;
29 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
30 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
31 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
32 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
33 import org.apache.myfaces.tobago.sanitizer.SanitizeMode;
34 import org.apache.myfaces.tobago.sanitizer.Sanitizer;
35 import org.apache.myfaces.tobago.util.ComponentUtils;
36 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
37
38 import javax.faces.component.EditableValueHolder;
39 import javax.faces.context.FacesContext;
40 import javax.faces.validator.LengthValidator;
41 import javax.faces.validator.RegexValidator;
42 import javax.faces.validator.Validator;
43 import java.io.IOException;
44
45 public class TextareaRenderer<T extends AbstractUITextarea> extends MessageLayoutRendererBase<T> {
46
47 @Override
48 protected boolean isOutputOnly(T component) {
49 return component.isDisabled() || component.isReadonly();
50 }
51
52 @Override
53 public HtmlElements getComponentTag() {
54 return HtmlElements.TOBAGO_TEXTAREA;
55 }
56
57 @Override
58 protected void setSubmittedValue(
59 final FacesContext facesContext, final EditableValueHolder component, final String newValue) {
60
61 String value = newValue;
62
63 final AbstractUITextarea textarea = (AbstractUITextarea) component;
64 if (ComponentUtils.getDataAttribute(textarea, "html-editor") != null
65 && SanitizeMode.auto == textarea.getSanitize()) {
66 final Sanitizer sanitizer = TobagoConfig.getInstance(facesContext).getSanitizer();
67 value = sanitizer.sanitize(newValue);
68 }
69
70
71 if (TobagoConfig.getInstance(facesContext).isDecodeLineFeed()) {
72 value = value.replace("\r\n", "\n");
73 }
74
75 super.setSubmittedValue(facesContext, textarea, value);
76 }
77
78 @Override
79 public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
80 final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
81 final String clientId = component.getClientId(facesContext);
82 final String fieldId = component.getFieldId(facesContext);
83 final Integer rows = component.getRows();
84 final boolean readonly = component.isReadonly();
85 final boolean disabled = component.isDisabled();
86 final Markup markup = component.getMarkup();
87 final TobagoResponseWriter writer = getResponseWriter(facesContext);
88
89 writer.startElement(HtmlElements.TEXTAREA);
90 writer.writeNameAttribute(clientId);
91 writer.writeIdAttribute(fieldId);
92 HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
93 writer.writeAttribute(HtmlAttributes.ROWS, rows);
94 writer.writeAttribute(HtmlAttributes.TITLE, title, true);
95 writer.writeAttribute(HtmlAttributes.READONLY, readonly);
96 writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
97 writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
98 writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
99
100 if (component.getAccessKey() != null) {
101 writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(component.getAccessKey()), false);
102 AccessKeyLogger.addAccessKey(facesContext, component.getAccessKey(), clientId);
103 }
104
105 writer.writeClassAttribute(
106 TobagoClass.TEXTAREA,
107 TobagoClass.TEXTAREA.createMarkup(component.getMarkup()),
108 BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
109 BootstrapClass.FORM_CONTROL,
110 component.getCustomClass(),
111 markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
112 int maxLength = 0;
113 int minLength = 0;
114 String pattern = null;
115 for (final Validator validator : component.getValidators()) {
116 if (validator instanceof LengthValidator) {
117 final LengthValidator lengthValidator = (LengthValidator) validator;
118 maxLength = lengthValidator.getMaximum();
119 minLength = lengthValidator.getMinimum();
120 } else if (validator instanceof RegexValidator) {
121 final RegexValidator regexValidator = (RegexValidator) validator;
122 pattern = regexValidator.getPattern();
123 }
124 }
125 if (maxLength > 0) {
126 writer.writeAttribute(HtmlAttributes.MAXLENGTH, maxLength);
127 }
128 if (minLength > 0) {
129 writer.writeAttribute(HtmlAttributes.MINLENGTH, minLength);
130 }
131 if (pattern != null) {
132 writer.writeAttribute(HtmlAttributes.PATTERN, pattern, true);
133 }
134
135 renderFocus(clientId, component.isFocus(), component.isError(), facesContext, writer);
136
137 final String placeholder = component.getPlaceholder();
138 if (!disabled && !readonly && StringUtils.isNotBlank(placeholder)) {
139 writer.writeAttribute(HtmlAttributes.PLACEHOLDER, placeholder, true);
140 }
141 String currentValue = RenderUtils.currentValue(component);
142 if (currentValue != null) {
143 if (ComponentUtils.getDataAttribute(component, "html-editor") != null
144 && SanitizeMode.auto == component.getSanitize()) {
145 final Sanitizer sanitizer = TobagoConfig.getInstance(facesContext).getSanitizer();
146 currentValue = sanitizer.sanitize(currentValue);
147 }
148
149 if (currentValue.startsWith("\r\n")) {
150 currentValue = "\r\n" + currentValue;
151 } else if (currentValue.startsWith("\n")) {
152 currentValue = "\n" + currentValue;
153 } else if (currentValue.startsWith("\r")) {
154 currentValue = "\r" + currentValue;
155 }
156 writer.writeText(currentValue);
157 }
158
159 writer.endElement(HtmlElements.TEXTAREA);
160 encodeBehavior(writer, facesContext, component);
161 }
162
163 @Override
164 protected void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
165 }
166
167 @Override
168 protected String getFieldId(final FacesContext facesContext, final T component) {
169 return component.getFieldId(facesContext);
170 }
171 }