(() -> {
+ final Div result = new Div();
+ result.addClassNames("item-grid-cell");
+ result.add(new Span(String.format("Row: %d. Column: %d.", row, column)));
+ final TextField text = new TextField("Class name: ", type.getSimpleName());
+ text.setValue(type.getSimpleName());
+ text.addClassName("highlighted");
+ text.addBlurListener(event -> text.setValue(type.getSimpleName()));
+ result.add(text);
+ return result;
+ }).withId(type.getSimpleName() + "-" + row + "-" + column);
+ }
+
+ private ItemGridGenerators() {
+ // no instances allowed
+ }
+
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/ItemGridProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/ItemGridProvider.java
new file mode 100644
index 00000000..e0e86578
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/ItemGridProvider.java
@@ -0,0 +1,61 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.component.Component;
+import com.vaadin.flow.component.orderedlayout.FlexComponent;
+import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.dates.SuperDatePicker;
+import org.vaadin.miki.superfields.dates.SuperDateTimePicker;
+import org.vaadin.miki.superfields.itemgrid.ItemGrid;
+import org.vaadin.miki.superfields.lazyload.ComponentObserver;
+import org.vaadin.miki.superfields.lazyload.LazyLoad;
+import org.vaadin.miki.superfields.lazyload.ObservedField;
+import org.vaadin.miki.superfields.numbers.SuperBigDecimalField;
+import org.vaadin.miki.superfields.numbers.SuperDoubleField;
+import org.vaadin.miki.superfields.numbers.SuperIntegerField;
+import org.vaadin.miki.superfields.numbers.SuperLongField;
+import org.vaadin.miki.superfields.tabs.SuperTabs;
+import org.vaadin.miki.superfields.unload.UnloadObserver;
+
+/**
+ * Provides an {@link ItemGrid}.
+ * @author miki
+ * @since 2020-11-18
+ */
+@Order(150)
+public class ItemGridProvider implements ComponentProvider
>> {
+
+ @Override
+ public ItemGrid> getComponent() {
+ return new ItemGrid>(
+ null,
+ () -> {
+ VerticalLayout result = new VerticalLayout();
+ result.setSpacing(true);
+ result.setPadding(true);
+ result.setAlignItems(FlexComponent.Alignment.STRETCH);
+ result.setWidthFull();
+ return result;
+ },
+ ItemGridGenerators::generateParagraph,
+ event -> {
+ if (event.isSelected())
+ event.getCellInformation().getComponent().getElement().getClassList().add("selected");
+ else event.getCellInformation().getComponent().getElement().getClassList().remove("selected");
+ },
+ SuperIntegerField.class, SuperLongField.class, SuperDoubleField.class,
+ SuperBigDecimalField.class, SuperDatePicker.class, SuperDateTimePicker.class,
+ SuperTabs.class, LazyLoad.class, ObservedField.class,
+ ComponentObserver.class, UnloadObserver.class, ItemGrid.class
+ )
+ .withRowComponentGenerator(rowNumber -> {
+ HorizontalLayout result = new HorizontalLayout();
+ result.setSpacing(true);
+ result.setAlignItems(FlexComponent.Alignment.CENTER);
+ result.setPadding(true);
+ return result;
+ });
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/MultiClickButtonProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/MultiClickButtonProvider.java
new file mode 100644
index 00000000..ad9735b8
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/MultiClickButtonProvider.java
@@ -0,0 +1,28 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.component.UI;
+import com.vaadin.flow.component.button.ButtonVariant;
+import com.vaadin.flow.component.icon.VaadinIcon;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.buttons.MultiClickButton;
+import org.vaadin.miki.superfields.buttons.SimpleButtonState;
+
+/**
+ * Provides {@link MultiClickButton}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(110)
+public class MultiClickButtonProvider implements ComponentProvider {
+
+ @Override
+ public MultiClickButton getComponent() {
+ return new MultiClickButton(
+ event -> UI.getCurrent().navigate(""),
+ new SimpleButtonState("Click to navigate to Info Page").withThemeVariant(ButtonVariant.LUMO_PRIMARY),
+ new SimpleButtonState("Are you sure?", VaadinIcon.INFO_CIRCLE.create()),
+ new SimpleButtonState("Really navigate away?", VaadinIcon.INFO.create()).withThemeVariant(ButtonVariant.LUMO_ERROR)
+ ).withId("multi-click-button");
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/ObservedFieldProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/ObservedFieldProvider.java
new file mode 100644
index 00000000..745f9a59
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/ObservedFieldProvider.java
@@ -0,0 +1,19 @@
+package org.vaadin.miki.demo.providers;
+
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.lazyload.ObservedField;
+
+/**
+ * Provides {@link ObservedField}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(100)
+public class ObservedFieldProvider implements ComponentProvider {
+
+ @Override
+ public ObservedField getComponent() {
+ return new ObservedField();
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperBigDecimalFieldProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperBigDecimalFieldProvider.java
new file mode 100644
index 00000000..395c0abc
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperBigDecimalFieldProvider.java
@@ -0,0 +1,29 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.numbers.SuperBigDecimalField;
+
+import java.math.BigDecimal;
+
+/**
+ * Provider for {@link SuperBigDecimalField}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(40)
+public class SuperBigDecimalFieldProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperBigDecimalField getComponent() {
+ return new SuperBigDecimalField(null, "Big decimal:").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal").withHelperText("(12 + 3 digits)");
+ }
+
+ @Override
+ public ValidationResult apply(BigDecimal bigDecimal, ValueContext valueContext) {
+ return bigDecimal != null && bigDecimal.longValue() % 2 == 0 ? ValidationResult.ok() : ValidationResult.error("only values with even integer part are allowed");
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDatePickerProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDatePickerProvider.java
new file mode 100644
index 00000000..036acfb3
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDatePickerProvider.java
@@ -0,0 +1,31 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.shared.dates.DatePatterns;
+import org.vaadin.miki.superfields.dates.SuperDatePicker;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+
+/**
+ * Provides {@link SuperDatePicker}.
+ * @author miki
+ * @since 2020-11-18
+ */
+@Order(50)
+public class SuperDatePickerProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperDatePicker getComponent() {
+ return new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now()).withHelperText("(default date pattern is YYYY-MM-DD)");
+ }
+
+ @Override
+ public ValidationResult apply(LocalDate localDate, ValueContext valueContext) {
+ return localDate != null && localDate.getDayOfWeek() == DayOfWeek.MONDAY ? ValidationResult.error("Mondays are not allowed") : ValidationResult.ok();
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDateTimePickerProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDateTimePickerProvider.java
new file mode 100644
index 00000000..7ee92c25
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDateTimePickerProvider.java
@@ -0,0 +1,30 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.shared.dates.DatePatterns;
+import org.vaadin.miki.superfields.dates.SuperDateTimePicker;
+
+import java.time.LocalDateTime;
+
+/**
+ * Provides {@link SuperDateTimePicker}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(60)
+public class SuperDateTimePickerProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperDateTimePicker getComponent() {
+ return new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now()).withHelperText("(default date pattern is month/day/year)");
+ }
+
+ @Override
+ public ValidationResult apply(LocalDateTime localDateTime, ValueContext valueContext) {
+ return localDateTime != null && localDateTime.getDayOfYear() < 50 ? ValidationResult.error("the first 50-or-so days of each year are not allowed") : ValidationResult.ok();
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDoubleFieldProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDoubleFieldProvider.java
new file mode 100644
index 00000000..e0907fa5
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperDoubleFieldProvider.java
@@ -0,0 +1,26 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.numbers.SuperDoubleField;
+
+/**
+ * Provider for {@link SuperDoubleField}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(30)
+public class SuperDoubleFieldProvider implements ComponentProvider, Validator {
+ @Override
+ public SuperDoubleField getComponent() {
+ return new SuperDoubleField(null, "Double:").withMaximumIntegerDigits(8).withMaximumFractionDigits(4).withHelperText("(8 + 4 digits)");
+ }
+
+ @Override
+ public ValidationResult apply(Double number, ValueContext valueContext) {
+ return number != null && number > 50 ? ValidationResult.ok() : ValidationResult.error("only even above 50 are accepted");
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/SuperFieldsGridItem.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperFieldsGridItem.java
similarity index 84%
rename from demo-v14/src/main/java/org/vaadin/miki/SuperFieldsGridItem.java
rename to demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperFieldsGridItem.java
index 1e1753df..01a2fd1f 100644
--- a/demo-v14/src/main/java/org/vaadin/miki/SuperFieldsGridItem.java
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperFieldsGridItem.java
@@ -1,4 +1,4 @@
-package org.vaadin.miki;
+package org.vaadin.miki.demo.providers;
/**
* Simple data class to showcase in grid select demo.
@@ -12,8 +12,8 @@ public class SuperFieldsGridItem {
private String name;
- SuperFieldsGridItem(Class> type) {
- this.name = type.getSimpleName();
+ SuperFieldsGridItem(String name) {
+ this.name = name;
this.nameLength = this.name.length();
}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperIntegerFieldProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperIntegerFieldProvider.java
new file mode 100644
index 00000000..376364fa
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperIntegerFieldProvider.java
@@ -0,0 +1,27 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.numbers.SuperIntegerField;
+
+/**
+ * Provider for {@link SuperIntegerField}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(10)
+public class SuperIntegerFieldProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperIntegerField getComponent() {
+ return new SuperIntegerField(null, "Integer:").withMaximumIntegerDigits(6).withHelperText("(6 digits)");
+ }
+
+ @Override
+ public ValidationResult apply(Integer integer, ValueContext valueContext) {
+ return integer != null && integer % 2 == 0 ? ValidationResult.ok() : ValidationResult.error("only even values are allowed");
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperLongFieldProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperLongFieldProvider.java
new file mode 100644
index 00000000..0dc5e0e6
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperLongFieldProvider.java
@@ -0,0 +1,27 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.numbers.SuperLongField;
+
+/**
+ * Provider for {@link SuperLongField}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(20)
+public class SuperLongFieldProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperLongField getComponent() {
+ return new SuperLongField(null, "Long:").withMaximumIntegerDigits(11).withId("long").withHelperText("(11 digits)");
+ }
+
+ @Override
+ public ValidationResult apply(Long integer, ValueContext valueContext) {
+ return integer != null && integer % 2 == 0 ? ValidationResult.ok() : ValidationResult.error("only even values are allowed");
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTabsProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTabsProvider.java
new file mode 100644
index 00000000..c9b2f72c
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTabsProvider.java
@@ -0,0 +1,30 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.component.html.Paragraph;
+import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.tabs.SuperTabs;
+
+import java.util.function.Supplier;
+
+/**
+ * Provides {@link SuperTabs}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(90)
+public class SuperTabsProvider implements ComponentProvider> {
+
+ @Override
+ public SuperTabs getComponent() {
+
+ return new SuperTabs((Supplier) HorizontalLayout::new)
+ .withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s))
+ .withItems(
+ "Java friendly", "Super-configurable", "Open source",
+ "Fun to use", "Reasonably well documented"
+ ).withId("super-tabs");
+ }
+
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTextAreaProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTextAreaProvider.java
new file mode 100644
index 00000000..6e37950e
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTextAreaProvider.java
@@ -0,0 +1,27 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.text.SuperTextArea;
+
+/**
+ * Provides {@link SuperTextArea}.
+ * @author miki
+ * @since 2020-11-17
+ */
+@Order(80)
+public class SuperTextAreaProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperTextArea getComponent() {
+ return new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area").withHelperText("(anything without ? goes)");
+ }
+
+ @Override
+ public ValidationResult apply(String s, ValueContext valueContext) {
+ return s != null && s.contains("?") ? ValidationResult.error("? is not allowed") : ValidationResult.ok();
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTextFieldProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTextFieldProvider.java
new file mode 100644
index 00000000..e96be6d8
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/SuperTextFieldProvider.java
@@ -0,0 +1,27 @@
+package org.vaadin.miki.demo.providers;
+
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.text.SuperTextField;
+
+/**
+ * Provides a {@link SuperTextField}.
+ * @author miki
+ * @since 2020-11-18
+ */
+@Order(70)
+public class SuperTextFieldProvider implements ComponentProvider, Validator {
+
+ @Override
+ public SuperTextField getComponent() {
+ return new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field").withHelperText("(anything without a ! goes)");
+ }
+
+ @Override
+ public ValidationResult apply(String s, ValueContext valueContext) {
+ return s != null && s.contains("!") ? ValidationResult.error("! is not allowed") : ValidationResult.ok();
+ }
+}
diff --git a/demo-v14/src/main/java/org/vaadin/miki/demo/providers/UnloadObserverProvider.java b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/UnloadObserverProvider.java
new file mode 100644
index 00000000..fb62f828
--- /dev/null
+++ b/demo-v14/src/main/java/org/vaadin/miki/demo/providers/UnloadObserverProvider.java
@@ -0,0 +1,19 @@
+package org.vaadin.miki.demo.providers;
+
+import org.vaadin.miki.demo.ComponentProvider;
+import org.vaadin.miki.demo.Order;
+import org.vaadin.miki.superfields.unload.UnloadObserver;
+
+/**
+ * Provides {@link UnloadObserver}.
+ * @author miki
+ * @since 2020-11-18
+ */
+@Order(140)
+public class UnloadObserverProvider implements ComponentProvider {
+
+ @Override
+ public UnloadObserver getComponent() {
+ return UnloadObserver.get().withoutQueryingOnUnload();
+ }
+}
diff --git a/pom.xml b/pom.xml
index f796be6e..fcd4c184 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
org.vaadin.miki
superfields-parent
- 0.9.1
+ 0.9.2
superfields
demo-v14
diff --git a/superfields/pom.xml b/superfields/pom.xml
index 69529c73..f22343a8 100644
--- a/superfields/pom.xml
+++ b/superfields/pom.xml
@@ -8,7 +8,7 @@
superfields
SuperFields
Code for various V14+ fields and other components.
- 0.9.1
+ 0.9.2
10
diff --git a/superfields/release-notes.md b/superfields/release-notes.md
index e60e46ed..716a7664 100644
--- a/superfields/release-notes.md
+++ b/superfields/release-notes.md
@@ -1,3 +1,11 @@
+# 0.9.2 - Bugfixes to number fields
+## New features and enhancements
+(nothing reported)
+## Changes to API
+(nothing reported)
+## Bug fixes
+* \#241 - [SuperBigDecimalField loses validation information](https://github.com/vaadin-miki/super-fields/issues/241)
+* \#243 - [Text selection mixin throws JS errors when used in Grid](https://github.com/vaadin-miki/super-fields/issues/243)
# 0.9.1 - Vaadin 14.4
## New features and enhancements
* \#224 - [Changing locale should preserve number precision information](https://github.com/vaadin-miki/super-fields/issues/224)
diff --git a/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java b/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java
index b004f55e..86958ec1 100644
--- a/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java
+++ b/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java
@@ -27,7 +27,9 @@
* The source component must implement {@link CanSelectText} and {@link CanReceiveSelectionEventsFromClient} and delegate them
* to this object.
* The client-side component must mix in {@code text-selection-mixin.js} or otherwise react to needed JS method calls.
- * Finally, the delegating class must implement a method {@code @ClientCallable void selectionChanged(int, int, String)}.
+ * Finally, the delegating class must implement methods: {@code @ClientCallable void selectionChanged(int, int, String)} and
+ * {@code @ClientCallable void reinitialiseEventListening()}. The first method should call this object's
+ * {@link #fireTextSelectionEvent(boolean, int, int, String)} and the second method should just be delegated to this object.
*
* @author miki
* @since 2020-06-01
@@ -115,7 +117,6 @@ public void selectNone() {
}
}
-
@Override
public void select(int from, int to) {
if(from <= to)
@@ -182,4 +183,12 @@ public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEven
this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient;
this.informClientAboutSendingEvents(receivingSelectionEventsFromClient);
}
+
+ /**
+ * This method should be called in response to {@code @ClientCallable void reinitialiseListeners()} on the owning object.
+ */
+ // fix for https://github.com/vaadin-miki/super-fields/issues/243 and the way components are initialised inside Grid
+ public void reinitialiseListeners() {
+ this.informClientAboutSendingEvents(this.isReceivingSelectionEventsFromClient());
+ }
}
diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java
index 4ca3ce51..5eb01b35 100644
--- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java
+++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java
@@ -349,6 +349,10 @@ protected void setPresentationValue(T number) {
String formatted = number == null ? "" : this.format.format(number);
LOGGER.debug("value {} to be presented as {} with {} decimal digits", number, formatted, this.format.getMaximumFractionDigits());
this.field.setValue(formatted);
+ // fixes #241 caused by a Vaadin bug https://github.com/vaadin/vaadin-text-field/issues/547
+ this.field.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.field, context ->
+ this.field.getElement().setProperty("invalid", super.isInvalid())
+ ));
}
/**
@@ -586,6 +590,7 @@ public String getErrorMessage() {
@Override
public void setInvalid(boolean invalid) {
+ super.setInvalid(invalid);
this.field.setInvalid(invalid);
}
diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java
index e0880908..ff7dad9a 100644
--- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java
+++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java
@@ -107,4 +107,9 @@ private void selectionChanged(int start, int end, String selection) {
this.delegate.fireTextSelectionEvent(true, start, end, selection);
}
+ @ClientCallable
+ private void reinitialiseListening() {
+ this.delegate.reinitialiseListeners();
+ }
+
}
diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java
index 2964356f..0a756aeb 100644
--- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java
+++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java
@@ -98,6 +98,11 @@ private void selectionChanged(int start, int end, String selection) {
this.delegate.fireTextSelectionEvent(true, start, end, selection);
}
+ @ClientCallable
+ private void reinitialiseListening() {
+ this.delegate.reinitialiseListeners();
+ }
+
@Override
public boolean isReceivingSelectionEventsFromClient() {
return this.delegate.isReceivingSelectionEventsFromClient();
diff --git a/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js b/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js
index 87c0b44d..d1292596 100644
--- a/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js
+++ b/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js
@@ -7,6 +7,7 @@ class SuperTextField extends TextSelectionMixin.to(TextFieldElement) {
setCallingServer(callingServer) {
console.log('STF: configuring event listeners; callingServer flag is '+callingServer);
+ console.log('STF: this now refers to '+this);
this.listenToEvents(this.inputElement, this, callingServer);
}
diff --git a/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js b/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js
index 3d469f5f..9b700539 100644
--- a/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js
+++ b/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js
@@ -46,22 +46,33 @@ export class TextSelectionMixin {
listenToEvents(inputComponent, webComponent, notifyServer) {
console.log('TSM: setting up text selection for component <'+webComponent.tagName+'>');
- if (webComponent.selectionMixin === undefined) {
- webComponent.selectionMixin = {
- input: inputComponent,
- callServer: notifyServer,
- startsAt: -1,
- endsAt: -1,
- selection: ''
+ if (inputComponent === undefined) {
+ console.log('TSM: input component is undefined, attempting to find it from shadow root/input element');
+ inputComponent = webComponent.inputElement;
+ if (inputComponent === undefined) {
+ console.warn('TSM: no input component, server will reinitialise this component shortly');
+ // this trick has been suggested by the magnificent Erik Lumme, thank you!
+ webComponent.$server.reinitialiseListening();
}
-
- const listener = () => webComponent.updateData(webComponent.selectionMixin, webComponent);
- inputComponent.addEventListener('mouseup', listener);
- inputComponent.addEventListener('keyup', listener);
- inputComponent.addEventListener('mouseleave', listener);
}
- else {
- webComponent.selectionMixin.callServer = notifyServer;
+ if (inputComponent !== undefined) {
+ console.log('TSM: input component is ' + inputComponent);
+ if (webComponent.selectionMixin === undefined) {
+ webComponent.selectionMixin = {
+ input: inputComponent,
+ callServer: notifyServer,
+ startsAt: -1,
+ endsAt: -1,
+ selection: ''
+ }
+
+ const listener = () => webComponent.updateData(webComponent.selectionMixin, webComponent);
+ inputComponent.addEventListener('mouseup', listener);
+ inputComponent.addEventListener('keyup', listener);
+ inputComponent.addEventListener('mouseleave', listener);
+ } else {
+ webComponent.selectionMixin.callServer = notifyServer;
+ }
}
}
}
diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java b/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java
index 0a72c8d0..d5c3401c 100644
--- a/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java
+++ b/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java
@@ -3,6 +3,10 @@
import com.github.mvysny.kaributesting.v10.MockVaadin;
import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
+import com.vaadin.flow.data.binder.Binder;
+import com.vaadin.flow.data.binder.ValidationResult;
+import com.vaadin.flow.data.binder.Validator;
+import com.vaadin.flow.data.binder.ValueContext;
import com.vaadin.flow.shared.Registration;
import org.junit.After;
import org.junit.Assert;
@@ -14,6 +18,7 @@
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -25,6 +30,62 @@
*/
class BaseTestsForIntegerNumbers {
+ public static final class NumberWrapper {
+ private X number;
+
+ public X getNumber() {
+ return number;
+ }
+
+ public void setNumber(X number) {
+ this.number = number;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NumberWrapper> that = (NumberWrapper>) o;
+ return Objects.equals(getNumber(), that.getNumber());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getNumber());
+ }
+ }
+
+ public static final class NumberValidator implements Validator {
+
+ private X referenceValue;
+
+ @Override
+ public ValidationResult apply(X x, ValueContext valueContext) {
+ return Objects.equals(x, this.referenceValue) ? ValidationResult.ok() : ValidationResult.error("nope");
+ }
+
+ public X getReferenceValue() {
+ return referenceValue;
+ }
+
+ public void setReferenceValue(X referenceValue) {
+ this.referenceValue = referenceValue;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NumberValidator> that = (NumberValidator>) o;
+ return Objects.equals(getReferenceValue(), that.getReferenceValue());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getReferenceValue());
+ }
+ }
+
private final Supplier> fieldSupplier;
private final T baseTestNumber;
private final T negativeTestNumber;
@@ -271,4 +332,35 @@ public void testChangesInLocaleDoNotAffectPrecision() {
Assert.assertEquals("max integer digits must not change when changing locale", maxDigits, this.field.getMaximumIntegerDigits());
}
+ @Test
+ public void testBinderAndValidation() {
+ final NumberWrapper wrapper = new NumberWrapper<>();
+ @SuppressWarnings("unchecked")
+ final Binder> binder = new Binder<>((Class>)(Class>)NumberWrapper.class);
+ final NumberValidator validator = new NumberValidator<>();
+ validator.setReferenceValue(this.baseTestNumber);
+ this.field.setNegativeValueAllowed(true);
+ binder.forField(this.field)
+ .withValidator(validator)
+ .bind("number");
+ binder.setBean(wrapper);
+ Assert.assertFalse("validator must fail with no number", binder.isValid());
+ wrapper.setNumber(this.baseTestNumber);
+ binder.setBean(wrapper);
+ Assert.assertTrue("validator must not fail with the correct number", binder.isValid());
+ wrapper.setNumber(this.negativeTestNumber);
+ binder.setBean(wrapper);
+ Assert.assertFalse("validator must fail with wrong number", binder.isValid());
+
+ this.field.setValue(this.baseTestNumber);
+ Assert.assertTrue("validator must be ok after field was changed to good number", binder.isValid());
+
+ validator.setReferenceValue(this.negativeTestNumber);
+ Assert.assertFalse("validator must not be ok after it was changed", binder.isValid());
+ validator.setReferenceValue(this.baseTestNumber);
+ this.field.setValue(this.baseTestNumber);
+ Assert.assertTrue("validator must be ok", binder.isValid());
+
+ }
+
}