org.dominokit.domino.ui.forms.ValueBox Maven / Gradle / Ivy
/*
* Copyright © 2019 Dominokit
*
* Licensed 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.dominokit.domino.ui.forms;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.dominokit.domino.ui.keyboard.KeyboardEvents.*;
import static org.jboss.elemento.Elements.label;
import static org.jboss.elemento.Elements.span;
import elemental2.dom.Element;
import elemental2.dom.EventListener;
import elemental2.dom.HTMLDivElement;
import elemental2.dom.HTMLElement;
import elemental2.dom.HTMLInputElement;
import elemental2.dom.HTMLLabelElement;
import elemental2.dom.Node;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import jsinterop.base.Js;
import org.dominokit.domino.ui.grid.flex.FlexItem;
import org.dominokit.domino.ui.grid.flex.FlexLayout;
import org.dominokit.domino.ui.style.Color;
import org.dominokit.domino.ui.utils.DominoElement;
import org.dominokit.domino.ui.utils.DominoUIConfig;
import org.dominokit.domino.ui.utils.ElementUtil;
import org.dominokit.domino.ui.utils.Focusable;
import org.dominokit.domino.ui.utils.HasChangeHandlers;
import org.dominokit.domino.ui.utils.HasPlaceHolder;
import org.dominokit.domino.ui.utils.IsReadOnly;
import org.dominokit.domino.ui.utils.LambdaFunction;
import org.gwtproject.safehtml.shared.SafeHtml;
import org.jboss.elemento.IsElement;
/**
* A base implementation for form elements that can have a value with extra features like focus,
* placeholders, change handlers
*
* @param The type of the component extending form this class
* @param The type of the HTML element that represent the root element of the component
* @param The type of the component value
*/
public abstract class ValueBox, E extends HTMLElement, V>
extends BasicFormElement
implements Focusable, HasPlaceHolder, IsReadOnly, HasChangeHandlers {
/** Constant css class name for a focused component */
public static final String FOCUSED = "focused";
/** Constant css class name for a component that has its labels floating above it */
public static final String FLOATING = "floating";
/** Constant css class name for a focused component */
public static final String DISABLED = "disabled";
protected final EventListener changeListener;
protected final EventListener inputListener;
private DominoElement inputElement;
protected DominoElement fieldGroup = DominoElement.div().css("field-group");
protected DominoElement fieldContainer = DominoElement.div().css("field-cntr");
protected FlexItem inputContainer = FlexItem.create();
private DominoElement notesContainer = DominoElement.div();
private FlexLayout leftAddOnsContainer = FlexLayout.create().css("field-lft-addons");
private FlexLayout rightAddOnsContainer = FlexLayout.create().css("field-rgt-addons");
private FlexItem helpItem;
private FlexItem countItem;
private FlexItem errorItem;
private FlexItem prefixItem = FlexItem.create().css("field-prefix");
private FlexItem postFixItem = FlexItem.create().css("field-postfix");
private DominoElement labelElement;
private DominoElement labelTextElement = DominoElement.of(span());
private Color focusColor = Color.BLUE;
private String placeholder;
private AutoValidator autoValidator;
protected List> changeHandlers = new ArrayList<>();
private final List> onClearHandlers = new ArrayList<>();
private boolean pauseChangeHandlers = false;
private boolean valid = true;
private boolean floating;
private boolean readOnly;
private String prefix;
private String postfix;
private DominoElement mandatoryAddOn;
private boolean validateOnFocusLost = true;
private FieldStyle fieldStyle = DominoUIConfig.INSTANCE.getDefaultFieldsStyle();
private FlexLayout fieldInnerContainer;
private boolean permaFloating = false;
private FlexLayout additionalInfoContainer;
private LambdaFunction noteInitializer;
private LambdaFunction labelInitializer;
/**
* @param type String type of the field input element
* @param label String
*/
public ValueBox(String type, String label) {
init((T) this);
noteInitializer =
() -> {
initNotesContainer();
noteInitializer = () -> {};
};
labelInitializer =
() -> {
labelElement = createLabelElement();
DominoElement.of(Js.uncheckedCast(getInputElement().element().parentElement))
.insertBefore(labelElement, inputElement);
linkLabelToField();
labelElement.addEventListener(
"click",
evt -> {
if (!isDisabled()) {
focus();
} else {
evt.stopPropagation();
evt.preventDefault();
}
});
labelInitializer = () -> {};
};
inputElement = DominoElement.of(createInputElement(type));
changeListener =
evt -> {
callChangeHandlers();
};
inputElement.addEventListener("change", changeListener);
inputElement.addEventListener("change", evt -> changeLabelFloating());
inputListener =
evt -> {
if (isEmpty()) {
showPlaceholder();
}
};
inputElement.addEventListener("input", inputListener);
onEnterKey();
layout();
setFocusColor(focusColor);
addFocusListeners();
setLabel(label);
setSpellCheck(true);
fieldStyle.apply(this);
DominoUIConfig.INSTANCE.getFixErrorsPosition().ifPresent(this::setFixErrorsPosition);
DominoUIConfig.INSTANCE.getFloatLabels().ifPresent(this::setFloating);
DominoUIConfig.INSTANCE
.getCondensed()
.ifPresent(
shouldCondense -> {
if (shouldCondense) {
condense();
}
});
}
protected void onEnterKey() {
listenOnKeyPress(getInputElement().element())
.onEnter(
evt -> {
if (DominoUIConfig.INSTANCE.isFocusNextFieldOnEnter()) {
getInputElement().blur();
List elements =
DominoElement.body().element().querySelectorAll(".field-group").asList();
int i = elements.indexOf(this.element());
if (i < elements.size() - 1) {
Element element = elements.get(i + 1);
Element input = element.querySelector("input");
Js.uncheckedCast(input).focus();
}
}
});
}
/** @return the {@link FieldStyle} */
public FieldStyle getFieldStyle() {
return fieldStyle;
}
/**
* Change the style of the field
*
* @param fieldStyle {@link FieldStyle}
* @return same implementing component
*/
public T setFieldStyle(FieldStyle fieldStyle) {
if (nonNull(fieldStyle)) {
fieldStyle.apply(this);
this.fieldStyle = fieldStyle;
}
return (T) this;
}
private void layout() {
fieldInnerContainer = FlexLayout.create();
fieldInnerContainer.appendChild(
inputContainer.css("field-input-cntr").setFlexGrow(1).appendChild(inputElement));
fieldGroup.appendChild(
fieldContainer.appendChild(
fieldInnerContainer.apply(
self -> {
mandatoryAddOn = createMandatoryAddOn();
if (nonNull(mandatoryAddOn)) {
self.appendChild(DominoElement.of(mandatoryAddOn).css("field-mandatory-addon"));
}
})));
}
private void initNotesContainer() {
helpItem = FlexItem.create().css("field-helper");
errorItem = FlexItem.create().hide().css("field-errors").setFlexGrow(1);
countItem = FlexItem.create().hide().css("field-counter");
additionalInfoContainer = FlexLayout.create();
notesContainer.css("notes-cntr");
fieldGroup.appendChild(
notesContainer
.css("field-note")
.appendChild(
additionalInfoContainer
.appendChild(helpItem.setFlexGrow(1))
.appendChild(errorItem)
.appendChild(countItem)));
}
/** {@inheritDoc} */
@Override
public T setFixErrorsPosition(boolean fixPosition) {
if (fixPosition) {
getErrorItem().show();
getErrorItem().style().setMinHeight("25px");
} else {
getErrorItem().style().setMinHeight("0px");
}
return super.setFixErrorsPosition(fixPosition);
}
/** this will set the attribute for on the label with the field id as a value */
protected void linkLabelToField() {
getLabelElement()
.ifPresent(
labelElement ->
labelElement.setAttribute("for", DominoElement.of(getInputElement()).getId()));
}
/** manually call the change handlers if they are not paused */
protected void callChangeHandlers() {
if (!pauseChangeHandlers) {
changeHandlers.forEach(changeHandler -> changeHandler.onValueChanged(getValue()));
}
}
/**
* create the label element for this component
*
* @return an {@link HTMLLabelElement} wrapped as {@link DominoElement}
*/
protected DominoElement createLabelElement() {
return DominoElement.of(label()).css("field-label");
}
/**
* Creates an input element with the specified type
*
* @param type String the input element type
* @return E the input html element
*/
protected abstract E createInputElement(String type);
private void addFocusListeners() {
inputElement.addEventListener("focus", evt -> doFocus());
inputElement.addEventListener(
"focusout",
evt -> {
doUnfocus();
if (isAutoValidation() && validateOnFocusLost) {
validate();
}
});
}
/**
* @param floating boolean, if true delegate to {@link #floating()} otherwise delegate to {@link
* #nonfloating()}
* @return same component instance
*/
public T setFloating(boolean floating) {
if (floating) {
floating();
} else {
nonfloating();
}
return (T) this;
}
/**
* Make the label always floating over the field even if the value is empty
*
* @return same component instance
*/
public T floating() {
floatLabel();
this.permaFloating = true;
showPlaceholder();
return (T) this;
}
/**
* Make the label floating over the field only when it has value
*
* @return same component instance
*/
public T nonfloating() {
unfloatLabel();
this.permaFloating = false;
hidePlaceholder();
return (T) this;
}
/** @return boolean, the current status of floating label */
public boolean isFloating() {
return floating;
}
/** @return the {@link FlexItem} that is added as a mandatoryAddOn */
public DominoElement getMandatoryAddOn() {
return mandatoryAddOn;
}
/** {@inheritDoc} */
@Override
public T focus() {
if (!isDisabled()) {
if (!isAttached()) {
ElementUtil.onAttach(
getInputElement(),
mutationRecord -> {
tryFocus();
});
} else {
tryFocus();
}
}
return (T) this;
}
private void tryFocus() {
getInputElement().element().focus();
doFocus();
}
/** {@inheritDoc} */
@Override
public T unfocus() {
if (!isAttached()) {
ElementUtil.onAttach(
getInputElement(),
mutationRecord -> {
getInputElement().element().blur();
doUnfocus();
});
} else {
getInputElement().element().blur();
doUnfocus();
}
return (T) this;
}
/** Focus the element and apply focus styles */
protected void doFocus() {
if (!isDisabled()) {
fieldGroup.addCss(FOCUSED);
floatLabel();
if (valid) {
if (isAddFocusColor()) {
fieldContainer.addCss("fc-" + focusColor.getStyle());
}
setLabelColor(focusColor);
}
showPlaceholder();
}
}
/** @return boolean, true if the field will add a focus color when focused, default to true */
protected boolean isAddFocusColor() {
return true;
}
/** un-focus the component and remove the focus styles */
protected void doUnfocus() {
fieldGroup.removeCss(FOCUSED);
fieldContainer.removeCss("fc-" + focusColor.getStyle(), FOCUSED);
unfloatLabel();
removeLabelColor(focusColor);
hidePlaceholder();
}
/** {@inheritDoc} */
@Override
protected void updateLabel(String label) {
if (isNull(labelTextElement)) {
labelTextElement = DominoElement.of(span());
}
labelTextElement.remove();
labelTextElement.setTextContent(label);
getLabelElement().ifPresent(labelElement -> labelElement.appendChild(labelTextElement));
}
/** {@inheritDoc} */
@Override
public Optional> getLabelTextElement() {
return Optional.of(labelTextElement);
}
/** @return same component instance */
public T hideLabelText() {
this.labelTextElement.hide();
return (T) this;
}
/** @return same component instance */
public T showLabelText() {
this.labelTextElement.show();
return (T) this;
}
/**
* Show/hide the label element text
*
* @param visible boolean
* @return same component instance
*/
public T setLabelTextVisible(boolean visible) {
this.labelTextElement.toggleDisplay(visible);
return (T) this;
}
/** {@inheritDoc} */
@Override
public boolean isFocused() {
return fieldGroup.style().containsCss(FOCUSED);
}
private void setLabelColor(Color color) {
if (nonNull(labelElement)) {
labelElement.addCss(color.getStyle());
}
}
private void removeLabelColor(Color color) {
if (nonNull(labelElement)) {
labelElement.removeCss(color.getStyle());
}
}
/** {@inheritDoc} */
@Override
public T enable() {
super.enable();
fieldGroup.removeCss(DISABLED);
return (T) this;
}
/** {@inheritDoc} */
@Override
public T disable() {
super.disable();
fieldGroup.addCss(DISABLED);
return (T) this;
}
/** {@inheritDoc} */
@Override
public T setLabel(String label) {
if (nonNull(label) && !label.isEmpty() || allowEmptyLabel()) {
labelInitializer.apply();
super.setLabel(label);
hidePlaceholder();
}
return (T) this;
}
protected boolean allowEmptyLabel() {
return false;
}
/**
* Sets the label as a custom element
*
* @param node {@link Node} label element
* @return same form element class
*/
public T setLabel(Node node) {
if (nonNull(node)) {
labelInitializer.apply();
super.setLabel(node);
}
return (T) this;
}
/**
* Sets the label from html
*
* @param safeHtml {@link SafeHtml}
* @return same form element class
*/
public T setLabel(SafeHtml safeHtml) {
if (nonNull(safeHtml)) {
labelInitializer.apply();
super.setLabel(safeHtml);
}
return (T) this;
}
/**
* Sets the label from an element
*
* @param element {@link IsElement}
* @return same form element class
*/
public T setLabel(IsElement> element) {
return setLabel(element.element());
}
/** {@inheritDoc} */
@Override
public T setPlaceholder(String placeholder) {
this.placeholder = placeholder;
showPlaceholder();
return (T) this;
}
protected void showPlaceholder() {
if (placeholder != null && shouldShowPlaceholder()) {
inputElement.setAttribute("placeholder", placeholder);
}
}
protected void hidePlaceholder() {
if (placeholder != null && !shouldShowPlaceholder()) {
inputElement.removeAttribute("placeholder");
}
}
protected boolean shouldShowPlaceholder() {
return isEmpty() && floating;
}
/** {@inheritDoc} */
@Override
public String getPlaceholder() {
return this.placeholder;
}
/** {@inheritDoc} */
@Override
public T setFocusColor(Color focusColor) {
removeLabelColor(this.focusColor);
if (isFocused()) {
setLabelColor(focusColor);
}
this.focusColor = focusColor;
return (T) this;
}
/** {@inheritDoc} */
@Override
public DominoElement getFieldInputContainer() {
return DominoElement.of(inputContainer);
}
/** {@inheritDoc} */
@Override
public DominoElement getFieldContainer() {
return DominoElement.of(fieldContainer);
}
/**
* Adds an element as an add on to the component at left side
*
* @param addon {@link FlexItem} that contains the add on element
* @return same component instance
*/
public T addLeftAddOn(FlexItem> addon) {
leftAddOnsContainer.appendChild(addon);
if (!leftAddOnsContainer.isAttached()) {
fieldInnerContainer.insertFirst(leftAddOnsContainer);
}
return (T) this;
}
/**
* wrap the element in a {@link FlexItem} and delegate to {@link #addLeftAddOn(FlexItem)}
*
* @param addon {@link IsElement}
* @return same component instance
*/
public T addLeftAddOn(IsElement> addon) {
return addLeftAddOn(FlexItem.create().appendChild(addon));
}
/**
* wrap the node in a {@link FlexItem} and delegate to {@link #addLeftAddOn(FlexItem)}
*
* @param addon {@link IsElement}
* @return same component instance
*/
public T addLeftAddOn(Node addon) {
return addLeftAddOn(FlexItem.create().appendChild(addon));
}
/**
* Adds an element as an add on to the component at left side
*
* @param rightAddon {@link FlexItem} that contains the add on element
* @return same component instance
*/
public T addRightAddOn(FlexItem> rightAddon) {
rightAddOnsContainer.appendChild(rightAddon);
if (!rightAddOnsContainer.isAttached()) {
fieldInnerContainer.appendChild(rightAddOnsContainer);
}
return (T) this;
}
/**
* wrap the element in a {@link FlexItem} and delegate to {@link #addRightAddOn(FlexItem)}
*
* @param addon {@link IsElement}
* @return same component instance
*/
public T addRightAddOn(IsElement> addon) {
addRightAddOn(FlexItem.create().appendChild(addon));
return (T) this;
}
/**
* wrap the node in a {@link FlexItem} and delegate to {@link #addRightAddOn(FlexItem)}
*
* @param addon {@link IsElement}
* @return same component instance
*/
public T addRightAddOn(Node addon) {
addRightAddOn(FlexItem.create().appendChild(addon));
return (T) this;
}
/**
* @param addon {@link FlexItem}
* @return same component instance
*/
public T removeRightAddOn(FlexItem addon) {
return removeRightAddOn(addon.element());
}
/**
* @param addon {@link IsElement}
* @return same component instance
*/
public T removeRightAddOn(IsElement> addon) {
return removeRightAddOn(addon.element());
}
/**
* @param addon {@link Node}
* @return same component instance
*/
public T removeRightAddOn(Node addon) {
return removeAddOn(rightAddOnsContainer, addon);
}
/**
* @param index int index of the addon to remove
* @return same component instance
*/
public T removeRightAddOn(int index) {
if (index >= 0 && index < rightAddOnsContainer.childNodes().length) {
return removeAddOn(rightAddOnsContainer, rightAddOnsContainer.childNodes().getAt(index));
}
return (T) this;
}
/**
* @param addon {@link FlexItem}
* @return same component instance
*/
public T removeLeftAddOn(FlexItem addon) {
return removeLeftAddOn(addon.element());
}
/**
* @param addon {@link IsElement}
* @return same component instance
*/
public T removeLeftAddOn(IsElement> addon) {
return removeLeftAddOn(addon.element());
}
/**
* @param addon {@link Node}
* @return same component instance
*/
public T removeLeftAddOn(Node addon) {
return removeAddOn(leftAddOnsContainer, addon);
}
/**
* @param index int index of the addon to remove
* @return same component instance
*/
public T removeLeftAddOn(int index) {
if (index >= 0 && index < leftAddOnsContainer.childNodes().length) {
return removeAddOn(leftAddOnsContainer, leftAddOnsContainer.childNodes().getAt(index));
}
return (T) this;
}
private T removeAddOn(FlexLayout container, Node addon) {
if (container.isAttached() && container.contains(addon)) {
if (container.hasDirectChild(addon)) {
container.removeChild(addon);
} else {
return removeAddOn(container, addon.parentNode);
}
}
return (T) this;
}
/**
* Remove all right addons
*
* @return same component instance
*/
public T removeRightAddOns() {
rightAddOnsContainer.clearElement();
return (T) this;
}
/**
* Remove all left addons
*
* @return same component instance
*/
public T removeLeftAddOns() {
leftAddOnsContainer.clearElement();
return (T) this;
}
/** {@inheritDoc} */
@Override
public DominoElement getInputElement() {
return DominoElement.of(inputElement);
}
/** {@inheritDoc} */
@Override
protected DominoElement getHelperContainer() {
noteInitializer.apply();
return DominoElement.of(helpItem.element());
}
/** {@inheritDoc} */
@Override
protected DominoElement getErrorsContainer() {
noteInitializer.apply();
return DominoElement.of(errorItem.element());
}
/** {@inheritDoc} */
@Override
public V getValue() {
return null;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return false;
}
/** {@inheritDoc} */
@Override
public boolean isEmptyIgnoreSpaces() {
return isEmpty();
}
/** {@inheritDoc} */
@Override
public String getStringValue() {
return null;
}
/** {@inheritDoc} */
@Override
public Optional> getLabelElement() {
if (nonNull(labelElement)) {
return Optional.of(DominoElement.of(labelElement));
}
return Optional.empty();
}
/** {@inheritDoc} */
@Override
public HTMLElement element() {
return fieldGroup.element();
}
/** {@inheritDoc} */
@Override
public T invalidate(String errorMessage) {
this.valid = false;
updateValidationStyles();
DominoUIConfig.INSTANCE
.getGlobalValidationHandler()
.onInvalidate(this, Collections.singletonList(errorMessage));
return super.invalidate(errorMessage);
}
/**
* flag the field to be used inside a table row
*
* @return same component instance
*/
public T asTableField() {
setTableField(true);
return (T) this;
}
/**
* based on the flag styles will be added or removed to make inside or outside of a table row
*
* @param asTableField boolean, if true adds the styles, otherwise removes them
* @return same component instance
*/
public T setTableField(boolean asTableField) {
if (asTableField) {
css("table-field");
} else {
removeCss("table-field");
}
return (T) this;
}
/** {@inheritDoc} */
@Override
public T invalidate(List errorMessages) {
this.valid = false;
updateValidationStyles();
DominoUIConfig.INSTANCE.getGlobalValidationHandler().onInvalidate(this, errorMessages);
return super.invalidate(errorMessages);
}
private void updateValidationStyles() {
fieldContainer.removeCss("fc-" + focusColor.getStyle());
fieldContainer.addCss("fc-" + Color.RED.getStyle());
removeLabelColor(focusColor);
setLabelColor(Color.RED);
changeLabelFloating();
}
/**
* pauses the validation when the field loses focus so they wont trigger
*
* @return same component instance
*/
public T pauseFocusValidation() {
this.validateOnFocusLost = false;
return (T) this;
}
/**
* resume the validation when the field loses focus so they trigger
*
* @return same component instance
*/
public T resumeFocusValidation() {
this.validateOnFocusLost = true;
return (T) this;
}
/** {@inheritDoc} */
@Override
public T clearInvalid() {
this.valid = true;
fieldContainer.addCss("fc-" + focusColor.getStyle());
fieldContainer.removeCss("fc-" + Color.RED.getStyle());
removeLabelColor(Color.RED);
if (isFocused()) {
doFocus();
} else {
doUnfocus();
}
changeLabelFloating();
DominoUIConfig.INSTANCE.getGlobalValidationHandler().onClearValidation(this);
return super.clearInvalid();
}
/** {@inheritDoc} */
@Override
public T setAutoValidation(boolean autoValidation) {
if (autoValidation) {
if (autoValidator == null) {
autoValidator = createAutoValidator(this::validate);
}
autoValidator.attach();
} else {
if (nonNull(autoValidator)) {
autoValidator.remove();
}
autoValidator = null;
}
return (T) this;
}
/** {@inheritDoc} */
@Override
public boolean isAutoValidation() {
return nonNull(autoValidator);
}
/**
* Create an AutoValidator that will automatically validate the component when it loses focus
*
* @param autoValidate {@link AutoValidate}
* @return same component instance
*/
protected abstract AutoValidator createAutoValidator(AutoValidate autoValidate);
/** {@inheritDoc} */
@Override
public T clear() {
return clear(false);
}
/** {@inheritDoc} */
@Override
public T clear(boolean silent) {
clearValue(silent);
autoValidate();
onClearHandlers.forEach(handler -> handler.accept((T) ValueBox.this));
return (T) this;
}
/** {@inheritDoc} */
@Override
public T value(V value) {
return value(value, false);
}
/** {@inheritDoc} */
@Override
public T value(V value, boolean silent) {
doSetValue(value);
changeLabelFloating();
autoValidate();
if (!silent) {
callChangeHandlers();
}
return (T) this;
}
/** {@inheritDoc} */
@Override
public T setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
if (readOnly) {
getInputElement().setAttribute(DISABLED, "true");
getInputElement().setAttribute("readonly", "true");
getInputElement().setAttribute(FLOATING, permaFloating);
css("readonly");
floating();
} else {
getInputElement().removeAttribute(DISABLED);
getInputElement().removeAttribute("readonly");
removeCss("readonly");
boolean floating;
if (getInputElement().hasAttribute(FLOATING)) {
floating = Boolean.parseBoolean(getInputElement().getAttribute(FLOATING));
} else {
floating = permaFloating;
}
setFloating(floating);
changeLabelFloating();
}
return (T) this;
}
/** {@inheritDoc} */
@Override
public boolean isReadOnly() {
return readOnly;
}
/** Changes the label floating state when the field get focus or lose focus */
protected void changeLabelFloating() {
if (!isEmpty() || isFocused()) floatLabel();
else unfloatLabel();
}
/** Make the label float over the component */
protected void floatLabel() {
if (!floating || permaFloating) {
if (!fieldGroup.containsCss(FLOATING)) {
fieldGroup.addCss(FLOATING);
}
this.floating = true;
}
}
/** unfloat a floating label */
protected void unfloatLabel() {
if ((floating && !permaFloating) && isEmpty()) {
fieldGroup.removeCss(FLOATING);
this.floating = false;
}
}
/** validate the component if auto validation is enabled */
protected void autoValidate() {
if (isAutoValidation()) validate();
}
/** {@inheritDoc} */
@Override
public T addChangeHandler(ChangeHandler super V> changeHandler) {
changeHandlers.add(changeHandler);
return (T) this;
}
/** {@inheritDoc} */
@Override
public T removeChangeHandler(ChangeHandler super V> changeHandler) {
changeHandlers.remove(changeHandler);
return (T) this;
}
/**
* Disable/Enable change handlers
*
* @param pauseChangeHandlers boolean, true to pause the change handlers, false to enable them
* @return same component instance
*/
public T setPauseChangeHandlers(boolean pauseChangeHandlers) {
this.pauseChangeHandlers = pauseChangeHandlers;
return (T) this;
}
/**
* Delagete to {@link #setPauseChangeHandlers(boolean)} with value true
*
* @return same component instance
*/
public T pauseChangeHandlers() {
return setPauseChangeHandlers(true);
}
/**
* Delagete to {@link #setPauseChangeHandlers(boolean)} with value false
*
* @return same component instance
*/
public T resumeChangeHandlers() {
return setPauseChangeHandlers(false);
}
/** @return the {@link FlexLayout} element that contains all left addons */
public FlexLayout getLeftAddonContainer() {
return leftAddOnsContainer;
}
/** @return the {@link FlexLayout} element that contains all right addons */
public FlexLayout getRightAddonContainer() {
return rightAddOnsContainer;
}
/** {@inheritDoc} */
@Override
public boolean hasChangeHandler(ChangeHandler super V> changeHandler) {
return changeHandlers.contains(changeHandler);
}
/**
* Enable/Disable spellcheck for the component, sets the spellcheck attribute
*
* @param spellCheck boolean, true to enable spellcheck, false to diable it
* @return same component instance
*/
public T setSpellCheck(boolean spellCheck) {
inputElement.setAttribute("spellcheck", spellCheck);
return (T) this;
}
/**
* Adds a handler that will be called when the field value is cleared
*
* @param onClearHandler {@link Consumer} of T
* @return same component instance
*/
public T addOnClearHandler(Consumer onClearHandler) {
this.onClearHandlers.add(onClearHandler);
return (T) this;
}
/**
* @param onClearHandler {@link Consumer} of T
* @return same component instance
*/
public T removeOnClearHandler(Consumer onClearHandler) {
this.onClearHandlers.remove(onClearHandler);
return (T) this;
}
/** @return a List of the clear handler for this component */
public List> getOnClearHandlers() {
return new ArrayList<>(onClearHandlers);
}
/**
* Adds a prefix text that will be a mandatory part of the field string value
*
* @param prefix String
* @return same component instance
*/
public T setPrefix(String prefix) {
if (!prefixItem.isAttached()) {
fieldInnerContainer.insertBefore(prefixItem, inputContainer);
}
this.prefixItem.setTextContent(prefix);
this.prefix = prefix;
return (T) this;
}
/** @return String */
public String getPrefix() {
return prefix;
}
/**
* Adds a postfix text that will be a mandatory part of the field string value
*
* @param postfix String
* @return same component instance
*/
public T setPostFix(String postfix) {
if (!postFixItem.isAttached()) {
fieldInnerContainer.insertAfter(postFixItem, inputContainer);
}
this.postFixItem.setTextContent(postfix);
this.postfix = postfix;
return (T) this;
}
/** @return the {@link HTMLDivElement} that groups the different elements of this component */
public DominoElement getFieldGroup() {
return fieldGroup;
}
/** @return the {@link FlexItem} that contains the input element of this component */
public FlexItem getInputContainer() {
return inputContainer;
}
/** @return the {@link HTMLDivElement} that contains the notes of this component */
public DominoElement getNotesContainer() {
noteInitializer.apply();
return notesContainer;
}
/** {@inheritDoc} */
@Override
public DominoElement getAdditionalInfoContainer() {
noteInitializer.apply();
return DominoElement.of(additionalInfoContainer);
}
/** @return the {@link FlexLayout} that contains all the left addons */
public FlexLayout getLeftAddOnsContainer() {
return leftAddOnsContainer;
}
/** @return the {@link FlexLayout} that contains all the right addons */
public FlexLayout getRightAddOnsContainer() {
return rightAddOnsContainer;
}
/** @return the {@link FlexItem} that contains the helper text of this component */
public FlexItem getHelpItem() {
noteInitializer.apply();
return helpItem;
}
/** @return the {@link FlexItem} that contains the character count for this component */
public FlexItem getCountItem() {
noteInitializer.apply();
return countItem;
}
/** @return the {@link FlexItem} that contains the error messages for this component */
public FlexItem getErrorItem() {
noteInitializer.apply();
return errorItem;
}
/** @return the {@link FlexItem} that contains the prefix text for this component */
public FlexItem getPrefixItem() {
return prefixItem;
}
/** @return the {@link FlexItem} that contains the postfix for this component */
public FlexItem getPostFixItem() {
return postFixItem;
}
/** @return the {@link Color} used to indicate focus of this field */
public Color getFocusColor() {
return focusColor;
}
/** @return String */
public String getPostfix() {
return postfix;
}
/** clear the field value */
protected void clearValue() {
clearValue(false);
};
/** clear the field value */
protected abstract void clearValue(boolean silent);
/** @param value V the value to set for this field */
protected abstract void doSetValue(V value);
/**
* Reduces the vertical spaces for this component to reduce its height
*
* @return same component instance
*/
public T condense() {
removeCss("condensed");
css("condensed");
return (T) this;
}
/**
* Increase the vertical spaces for this component to increase its height
*
* @return same component instance
*/
public T spread() {
removeCss("condensed");
return (T) this;
}
/** @return the {@link FlexItem} that contains the mandatory addons */
protected DominoElement createMandatoryAddOn() {
return null;
}
/** Implementations of this interface will apply the validations for a component */
public interface AutoValidate {
/** Applies the validations */
void apply();
}
/**
* A class to wrap an {@link AutoValidate} and provide the ability to attach/remove it from a
* component
*/
public abstract static class AutoValidator {
protected AutoValidate autoValidate;
/** @param autoValidate {@link AutoValidate} */
public AutoValidator(AutoValidate autoValidate) {
this.autoValidate = autoValidate;
}
/** Attach the {@link AutoValidate} to the component */
public abstract void attach();
/** Remove the {@link AutoValidate} from the component */
public abstract void remove();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy