blob: 9cd6bca55017689fd904108a847a4e4a4daf6c44 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.tobago.internal.renderkit.renderer;
import org.apache.myfaces.tobago.component.Attributes;
import org.apache.myfaces.tobago.component.Facets;
import org.apache.myfaces.tobago.component.RendererTypes;
import org.apache.myfaces.tobago.internal.component.AbstractUIButton;
import org.apache.myfaces.tobago.internal.component.AbstractUIIn;
import org.apache.myfaces.tobago.internal.component.AbstractUIInput;
import org.apache.myfaces.tobago.internal.component.AbstractUIOut;
import org.apache.myfaces.tobago.internal.component.AbstractUISelectOneChoice;
import org.apache.myfaces.tobago.internal.util.AccessKeyLogger;
import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
import org.apache.myfaces.tobago.internal.util.RenderUtils;
import org.apache.myfaces.tobago.internal.util.StringUtils;
import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
import org.apache.myfaces.tobago.renderkit.css.CssItem;
import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
import org.apache.myfaces.tobago.util.ComponentUtils;
import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.LengthValidator;
import javax.faces.validator.RegexValidator;
import javax.faces.validator.Validator;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
public class InRenderer extends MessageLayoutRendererBase {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Override
public HtmlElements getComponentTag() {
return HtmlElements.TOBAGO_IN;
}
@Override
protected void encodeBeginField(final FacesContext facesContext, final UIComponent component)
throws IOException {
final AbstractUIIn input = (AbstractUIIn) component;
final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, input);
final String currentValue = getCurrentValue(facesContext, input);
final boolean password = ComponentUtils.getBooleanAttribute(input, Attributes.password);
if (LOG.isDebugEnabled()) {
LOG.debug("currentValue = '{}'", StringUtils.toConfidentialString(currentValue, password));
}
final HtmlInputTypes type = password ? HtmlInputTypes.PASSWORD : HtmlInputTypes.TEXT;
final String clientId = input.getClientId(facesContext);
final String fieldId = input.getFieldId(facesContext);
final boolean readonly = input.isReadonly();
final boolean disabled = input.isDisabled();
final boolean required = ComponentUtils.getBooleanAttribute(input, Attributes.required);
final TobagoResponseWriter writer = getResponseWriter(facesContext);
final UIComponent after = ComponentUtils.getFacet(input, Facets.after);
final UIComponent before = ComponentUtils.getFacet(input, Facets.before);
if (after != null || before != null) {
writer.startElement(HtmlElements.DIV); // Wrapping the field to fix input groups with flexLeft/flexRight
writer.writeClassAttribute(TobagoClass.INPUT__GROUP__OUTER);
writer.startElement(HtmlElements.DIV);
writer.writeClassAttribute(BootstrapClass.INPUT_GROUP);
}
encodeGroupAddon(facesContext, writer, before, false);
writer.startElement(HtmlElements.INPUT);
if (input.getAccessKey() != null) {
writer.writeAttribute(HtmlAttributes.ACCESSKEY, Character.toString(input.getAccessKey()), false);
AccessKeyLogger.addAccessKey(facesContext, input.getAccessKey(), clientId);
}
writer.writeAttribute(HtmlAttributes.TYPE, type);
writer.writeNameAttribute(clientId);
writer.writeIdAttribute(fieldId);
HtmlRendererUtils.writeDataAttributes(facesContext, writer, input);
if (currentValue != null && !password) {
writer.writeAttribute(HtmlAttributes.VALUE, currentValue, true);
}
if (title != null) {
writer.writeAttribute(HtmlAttributes.TITLE, title, true);
}
int maxLength = 0;
int minLength = 0;
String pattern = null;
for (final Validator validator : input.getValidators()) {
if (validator instanceof LengthValidator) {
final LengthValidator lengthValidator = (LengthValidator) validator;
maxLength = lengthValidator.getMaximum();
minLength = lengthValidator.getMinimum();
} else if (validator instanceof RegexValidator) {
final RegexValidator regexValidator = (RegexValidator) validator;
pattern = regexValidator.getPattern();
}
}
if (maxLength > 0) {
writer.writeAttribute(HtmlAttributes.MAXLENGTH, maxLength);
}
if (minLength > 0) {
writer.writeAttribute(HtmlAttributes.MINLENGTH, minLength);
}
if (pattern != null) {
writer.writeAttribute(HtmlAttributes.PATTERN, pattern, true);
}
writer.writeAttribute(HtmlAttributes.READONLY, readonly);
writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
writer.writeAttribute(HtmlAttributes.TABINDEX, input.getTabIndex());
if (!disabled && !readonly) {
writer.writeAttribute(HtmlAttributes.PLACEHOLDER, input.getPlaceholder(), true);
}
final CssItem rendererCssClass = getRendererCssClass();
writer.writeClassAttribute(
rendererCssClass,
// rendererCssClass != null ? rendererCssClass.createMarkup(markup) : null,
BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(input)),
BootstrapClass.FORM_CONTROL,
input.getCustomClass());
writer.writeAttribute(HtmlAttributes.REQUIRED, required);
HtmlRendererUtils.renderFocus(clientId, input.isFocus(), ComponentUtils.isError(input), facesContext, writer);
writeAdditionalAttributes(facesContext, writer, input);
writer.endElement(HtmlElements.INPUT);
encodeBehavior(writer, facesContext, input);
encodeGroupAddon(facesContext, writer, after, true);
if (after != null || before != null) {
writer.endElement(HtmlElements.DIV);
writer.endElement(HtmlElements.DIV);
}
}
private void encodeGroupAddon(
final FacesContext facesContext, final TobagoResponseWriter writer, final UIComponent addon,
final boolean isAfterFacet) throws IOException {
if (addon != null) {
for (final UIComponent child : RenderUtils.getFacetChildren(addon)) {
if (child instanceof AbstractUIButton && ((AbstractUIButton) child).isParentOfCommands()) {
if (isAfterFacet) {
child.setRendererType(RendererTypes.ButtonInsideInAfter.name());
} else {
child.setRendererType(RendererTypes.ButtonInsideIn.name());
}
child.encodeAll(facesContext);
} else {
writer.startElement(HtmlElements.DIV);
writer.writeClassAttribute(isAfterFacet
? BootstrapClass.INPUT_GROUP_APPEND : BootstrapClass.INPUT_GROUP_PREPEND);
if (child instanceof AbstractUIButton) {
child.encodeAll(facesContext);
} else if (child instanceof AbstractUIOut) {
child.setRendererType(RendererTypes.OutInsideIn.name());
child.encodeAll(facesContext);
} else if (child instanceof AbstractUISelectOneChoice) {
child.setRendererType(RendererTypes.SelectOneChoiceInsideIn.name());
child.encodeAll(facesContext);
} else {
writer.startElement(HtmlElements.SPAN);
writer.writeClassAttribute(BootstrapClass.INPUT_GROUP_TEXT);
child.encodeAll(facesContext);
writer.endElement(HtmlElements.SPAN);
}
writer.endElement(HtmlElements.DIV);
}
}
}
}
@Override
protected void encodeEndField(final FacesContext facesContext, final UIComponent component) throws IOException {
}
protected CssItem getRendererCssClass() {
return TobagoClass.IN;
}
protected void writeAdditionalAttributes(
final FacesContext facesContext, final TobagoResponseWriter writer, final AbstractUIInput input)
throws IOException {
}
@Override
protected String getFieldId(final FacesContext facesContext, final UIComponent component) {
final AbstractUIInput input = (AbstractUIInput) component;
return input.getFieldId(facesContext);
}
}