com.vaadin.flow.component.textfield.EmailField Maven / Gradle / Ivy
/**
* Copyright 2000-2024 Vaadin Ltd.
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See {@literal } for the full
* license.
*/
package com.vaadin.flow.component.textfield;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.CompositionNotifier;
import com.vaadin.flow.component.HasHelper;
import com.vaadin.flow.component.HasLabel;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.InputNotifier;
import com.vaadin.flow.component.KeyNotifier;
import com.vaadin.flow.component.shared.ClientValidationUtil;
import com.vaadin.flow.component.shared.HasClientValidation;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.HasValidator;
import com.vaadin.flow.data.binder.ValidationStatusChangeEvent;
import com.vaadin.flow.data.binder.ValidationStatusChangeListener;
import com.vaadin.flow.data.binder.Validator;
import com.vaadin.flow.data.value.HasValueChangeMode;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.function.DeploymentConfiguration;
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.shared.Registration;
/**
* Server-side component for the {@code vaadin-email-field} element.
*
* @author Vaadin Ltd.
*/
public class EmailField extends GeneratedVaadinEmailField
implements HasSize, HasValidation, HasValueChangeMode,
HasPrefixAndSuffix, InputNotifier, KeyNotifier, CompositionNotifier,
HasAutocomplete, HasAutocapitalize, HasAutocorrect, HasHelper, HasLabel,
HasValidator, HasClientValidation {
private static final String EMAIL_PATTERN = "^" + "([a-zA-Z0-9_\\.\\-+])+" // local
+ "@" + "[a-zA-Z0-9-.]+" // domain
+ "\\." + "[a-zA-Z0-9-]{2,}" // tld
+ "$";
private ValueChangeMode currentMode;
private boolean isConnectorAttached;
private int valueChangeTimeout = DEFAULT_CHANGE_TIMEOUT;
private TextFieldValidationSupport validationSupport;
/**
* Constructs an empty {@code EmailField}.
*/
public EmailField() {
super("", "", false);
// workaround for https://github.com/vaadin/flow/issues/3496
setInvalid(false);
setValueChangeMode(ValueChangeMode.ON_CHANGE);
addValueChangeListener(e -> validate());
if (isEnforcedFieldValidationEnabled()) {
addClientValidatedEventListener(e -> validate());
}
}
/**
* Constructs an empty {@code EmailField} with the given label.
*
* @param label
* the text to set as the label
*/
public EmailField(String label) {
this();
setLabel(label);
}
/**
* Constructs an empty {@code EmailField} with the given label and
* placeholder text.
*
* @param label
* the text to set as the label
* @param placeholder
* the placeholder text to set
*/
public EmailField(String label, String placeholder) {
this(label);
setPlaceholder(placeholder);
}
/**
* Constructs an empty {@code EmailField} with a value change listener.
*
* @param listener
* the value change listener
*
* @see #addValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener)
*/
public EmailField(
ValueChangeListener> listener) {
this();
addValueChangeListener(listener);
}
/**
* Constructs an empty {@code EmailField} with a value change listener and a
* label.
*
* @param label
* the text to set as the label
* @param listener
* the value change listener
*
* @see #setLabel(String)
* @see #addValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener)
*/
public EmailField(String label,
ValueChangeListener> listener) {
this(label);
addValueChangeListener(listener);
}
/**
* Constructs a {@code EmailField} with a value change listener, a label and
* an initial value.
*
* @param label
* the text to set as the label
* @param initialValue
* the initial value
* @param listener
* the value change listener
*
* @see #setLabel(String)
* @see #setValue(Object)
* @see #addValueChangeListener(com.vaadin.flow.component.HasValue.ValueChangeListener)
*/
public EmailField(String label, String initialValue,
ValueChangeListener> listener) {
this(label);
setValue(initialValue);
addValueChangeListener(listener);
}
private TextFieldValidationSupport getValidationSupport() {
if (validationSupport == null) {
validationSupport = new TextFieldValidationSupport(this);
validationSupport.setPattern(EMAIL_PATTERN);
}
return validationSupport;
}
/**
* {@inheritDoc}
*
* The default value is {@link ValueChangeMode#ON_CHANGE}.
*/
@Override
public ValueChangeMode getValueChangeMode() {
return currentMode;
}
@Override
public void setValueChangeMode(ValueChangeMode valueChangeMode) {
currentMode = valueChangeMode;
setSynchronizedEvent(
ValueChangeMode.eventForMode(valueChangeMode, "value-changed"));
applyChangeTimeout();
}
@Override
public void setValueChangeTimeout(int valueChangeTimeout) {
this.valueChangeTimeout = valueChangeTimeout;
applyChangeTimeout();
}
@Override
public int getValueChangeTimeout() {
return valueChangeTimeout;
}
private void applyChangeTimeout() {
ValueChangeMode.applyChangeTimeout(getValueChangeMode(),
getValueChangeTimeout(), getSynchronizationRegistration());
}
@Override
public String getErrorMessage() {
return super.getErrorMessageString();
}
@Override
public void setErrorMessage(String errorMessage) {
super.setErrorMessage(errorMessage);
}
@Override
public boolean isInvalid() {
return isInvalidBoolean();
}
@Override
public void setInvalid(boolean invalid) {
super.setInvalid(invalid);
}
/**
* Sets the label for this component.
*
* @param label
* value for the {@code label} property in the webcomponent
*/
@Override
public void setLabel(String label) {
super.setLabel(label);
}
/**
* String used for the label element.
*
* @return the {@code label} property from the webcomponent
*/
@Override
public String getLabel() {
return getLabelString();
}
@Override
public void setPlaceholder(String placeholder) {
super.setPlaceholder(placeholder);
}
/**
* A hint to the user of what can be entered in the component.
*
* @return the {@code placeholder} property from the webcomponent
*/
public String getPlaceholder() {
return getPlaceholderString();
}
@Override
public void setAutofocus(boolean autofocus) {
super.setAutofocus(autofocus);
}
/**
* Specify that this control should have input focus when the page loads.
*
* @return the {@code autofocus} property from the webcomponent
*/
public boolean isAutofocus() {
return isAutofocusBoolean();
}
/**
* Maximum number of characters (in Unicode code points) that the user can
* enter.
*
* @param maxLength
* the maximum length
*/
public void setMaxLength(int maxLength) {
super.setMaxlength(maxLength);
getValidationSupport().setMaxLength(maxLength);
}
/**
* Maximum number of characters (in Unicode code points) that the user can
* enter.
*
* @return the {@code maxlength} property from the webcomponent
*/
public int getMaxLength() {
return (int) getMaxlengthDouble();
}
/**
* Minimum number of characters (in Unicode code points) that the user can
* enter.
*
* @param minLength
* the minimum length
*/
public void setMinLength(int minLength) {
super.setMinlength(minLength);
getValidationSupport().setMinLength(minLength);
}
/**
* Minimum number of characters (in Unicode code points) that the user can
* enter.
*
* @return the {@code minlength} property from the webcomponent
*/
public int getMinLength() {
return (int) getMinlengthDouble();
}
/**
* When set to true
, user is prevented from typing a value that
* conflicts with the given {@code pattern}.
*
* @return the {@code preventInvalidInput} property from the webcomponent
*/
public boolean isPreventInvalidInput() {
return isPreventInvalidInputBoolean();
}
@Override
public void setPreventInvalidInput(boolean preventInvalidInput) {
super.setPreventInvalidInput(preventInvalidInput);
}
@Override
public void setPattern(String pattern) {
super.setPattern(pattern);
getValidationSupport().setPattern(pattern);
}
/**
* A regular expression that the value is checked against. The pattern must
* match the entire value, not just some subset.
*
* @return the {@code pattern} property from the webcomponent
*/
public String getPattern() {
return getPatternString();
}
/**
* The text usually displayed in a tooltip popup when the mouse is over the
* field.
*
* @return the {@code title} property from the webcomponent
*/
public String getTitle() {
return super.getTitleString();
}
@Override
public void setTitle(String title) {
super.setTitle(title);
}
/**
* Specifies if the field value gets automatically selected when the field
* gains focus.
*
* @return true
if autoselect is active, false
* otherwise
*/
public boolean isAutoselect() {
return super.isAutoselectBoolean();
}
/**
* Set to true
to always have the field value automatically
* selected when the field gains focus, false
otherwise.
*
* @param autoselect
* true
to set auto select on, false
* otherwise
*/
@Override
public void setAutoselect(boolean autoselect) {
super.setAutoselect(autoselect);
}
/**
* Gets the visibility state of the button which clears the email field.
*
* @return true
if the button is visible, false
* otherwise
*/
public boolean isClearButtonVisible() {
return isClearButtonVisibleBoolean();
}
/**
* Set to false
to hide the clear button which clears the email
* field.
*
* @param clearButtonVisible
* true
to set the button visible,
* false
otherwise
*/
@Override
public void setClearButtonVisible(boolean clearButtonVisible) {
super.setClearButtonVisible(clearButtonVisible);
}
@Override
public String getEmptyValue() {
return "";
}
/**
* Sets the value of this email field. If the new value is not equal to
* {@code getValue()}, fires a value change event. Throws
* {@code NullPointerException}, if the value is null.
*
* Note: {@link Binder} will take care of the {@code null} conversion when
* integrates with email field, as long as no new converter is defined.
*
* @param value
* the new value, not {@code null}
*/
@Override
public void setValue(String value) {
super.setValue(value);
}
/**
* Returns the current value of the email field. By default, the empty email
* field will return an empty string.
*
* @return the current value.
*/
@Override
public String getValue() {
return super.getValue();
}
@Override
public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) {
super.setRequiredIndicatorVisible(requiredIndicatorVisible);
getValidationSupport().setRequired(requiredIndicatorVisible);
}
@Override
public Validator getDefaultValidator() {
if (isEnforcedFieldValidationEnabled()) {
return (value, context) -> getValidationSupport()
.checkValidity(value);
}
return Validator.alwaysPass();
}
@Override
public Registration addValidationStatusChangeListener(
ValidationStatusChangeListener listener) {
if (isEnforcedFieldValidationEnabled()) {
return addClientValidatedEventListener(
event -> listener.validationStatusChanged(
new ValidationStatusChangeEvent(this,
!isInvalid())));
}
return null;
}
/**
* Performs server-side validation of the current value. This is needed
* because it is possible to circumvent the client-side validation
* constraints using browser development tools.
*/
@Override
protected void validate() {
setInvalid(getValidationSupport().isInvalid(getValue()));
}
@Override
protected void onAttach(AttachEvent attachEvent) {
super.onAttach(attachEvent);
if (isEnforcedFieldValidationEnabled()) {
ClientValidationUtil
.preventWebComponentFromModifyingInvalidState(this);
} else {
FieldValidationUtil.disableClientValidation(this);
}
}
/**
* Whether the full experience validation is enforced for the component.
*
* Exposed with protected visibility to support mocking
*
* The method requires the {@code VaadinSession} instance to obtain the
* application configuration properties, otherwise, the feature is
* considered disabled.
*
* @return {@code true} if enabled, {@code false} otherwise.
*/
protected boolean isEnforcedFieldValidationEnabled() {
VaadinSession session = VaadinSession.getCurrent();
if (session == null) {
return false;
}
DeploymentConfiguration configuration = session.getConfiguration();
if (configuration == null) {
return false;
}
return configuration.isEnforcedFieldValidationEnabled();
}
}