diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/DelayedActionConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/DelayedActionConfig.java new file mode 100644 index 000000000..04bcd5b3e --- /dev/null +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/DelayedActionConfig.java @@ -0,0 +1,48 @@ +/* + * 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.config; + +public interface DelayedActionConfig extends ComponentConfig { + + /** + * Use to globally configure the delayed actions delay. + * + * @return the delay in milliseconds, default to 200ms + */ + default int getDelayedExecutionDefaultDelay() { + return 200; + } + + default int getDefaultSelectableBoxTypeAheadDelay() { + return 1000; + } + + default int getSuggestBoxTypeAheadDelay() { + return getDefaultSelectableBoxTypeAheadDelay(); + } + + default int getSelectBoxTypeAheadDelay() { + return getDefaultSelectableBoxTypeAheadDelay(); + } + + default int getDefaultNotificationDuration() { + return 4000; + } + + default int getDateBoxDefaultInputParseDelay() { + return getDelayedExecutionDefaultDelay(); + } +} diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/SearchConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/SearchConfig.java index e1d9e41cf..7eb990eaa 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/config/SearchConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/SearchConfig.java @@ -19,7 +19,7 @@ * Implementations of this interface can be used to configure defaults for {@link * org.dominokit.domino.ui.search.SearchBox} component */ -public interface SearchConfig extends ComponentConfig { +public interface SearchConfig extends DelayedActionConfig { /** * Use this method to define the default auto search delay for SearchBox in milliseconds @@ -29,7 +29,7 @@ public interface SearchConfig extends ComponentConfig { * @return an integer delay in milliseconds */ default int getAutoSearchDelay() { - return 200; + return getDelayedExecutionDefaultDelay(); } /** diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/UIConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/UIConfig.java index 0811b5548..a39c60517 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/config/UIConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/UIConfig.java @@ -29,4 +29,5 @@ public interface UIConfig UploadConfig, StepperConfig, CalendarConfig, - TimePickerConfig {} + TimePickerConfig, + DelayedActionConfig {} diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/Calendar.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/Calendar.java index 2ae43e194..4160f814b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/Calendar.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/Calendar.java @@ -134,11 +134,10 @@ public Calendar(Date date, DateTimeFormatInfo dateTimeFormatInfo, CalendarInitCo evt.stopPropagation(); CalendarCustomEvents.UpdateDateEventData dateData = CalendarCustomEvents.UpdateDateEventData.of((CustomEvent) evt); - Date updatedDate = new Date(dateData.getTimestamp()); - onDateViewUpdate(updatedDate); + this.date = new Date(dateData.getTimestamp()); + onDateViewUpdate(this.date); calendarMonth.show(); yearMonthPicker.hide(); - this.date = updatedDate; }); this.root.addEventListener( @@ -148,9 +147,8 @@ public Calendar(Date date, DateTimeFormatInfo dateTimeFormatInfo, CalendarInitCo CalendarCustomEvents.UpdateDateEventData dateData = CalendarCustomEvents.UpdateDateEventData.of((CustomEvent) evt); Date oldDate = this.date; - Date updatedDate = new Date(dateData.getTimestamp()); - this.date = updatedDate; - onDateSelectionChanged(updatedDate); + this.date = new Date(dateData.getTimestamp()); + onDateSelectionChanged(this.date); calendarMonth.show(); yearMonthPicker.hide(); triggerChangeListeners(oldDate, this.date); @@ -313,6 +311,17 @@ public Calendar setDate(Date date) { return this; } + /** + * Resets the calendar view to the month view if it is on month/year selection view + * + * @return same Calendar instance + */ + public Calendar resetView() { + calendarMonth.show(); + yearMonthPicker.hide(); + return this; + } + /** @return the {@link DateTimeFormatInfo} used by this calendar instance */ @Override public DateTimeFormatInfo getDateTimeFormatInfo() { diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/DateBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/DateBox.java index 7c4bda3a4..dfdcdcabe 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/DateBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/DateBox.java @@ -149,6 +149,7 @@ public DateBox( .setOpenOnClick(this.openOnClick) .setPosition(BEST_MIDDLE_DOWN_UP) .appendChild(this.calendar) + .addCloseListener(component -> calendar.resetView()) .addOnRemoveListener( popover -> { withOpenOnFocusToggleListeners(false, field -> focus()); @@ -183,13 +184,37 @@ public DateBox( clearInvalid(); } catch (IllegalArgumentException ignored) { if (parseStrict) { - invalidate("Unable to parse date value " + value); + invalidate(getLabels().calendarInvalidDateFormat(value)); } DomGlobal.console.warn("Unable to parse date value " + value); } } }); + getInputElement() + .addEventListener( + "input", + evt -> { + DelayedExecution.execute( + () -> { + String value = getStringValue(); + if (value.isEmpty()) { + clear(); + } else { + try { + withValue(getFormattedValue(value)); + clearInvalid(); + } catch (IllegalArgumentException ignored) { + if (parseStrict) { + invalidate(getLabels().calendarInvalidDateFormat(value)); + } + DomGlobal.console.warn("Unable to parse date value " + value); + } + } + }, + config().getUIConfig().getDateBoxDefaultInputParseDelay()); + }); + appendChild( PrimaryAddOn.of( getConfig() diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/TimeBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/TimeBox.java index fc622922a..59237b8e4 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/TimeBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/TimeBox.java @@ -158,7 +158,7 @@ public TimeBox(Date date, DateTimeFormatInfo dateTimeFormatInfo) { clearInvalid(); } catch (IllegalArgumentException ignored) { if (parseStrict) { - invalidate("Unable to parse date value " + value); + invalidate(getLabels().timePickerInvalidTimeFormat(value)); } DomGlobal.console.warn("Unable to parse date value " + value); } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSelect.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSelect.java index 04d1b98f4..e073e8a54 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSelect.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSelect.java @@ -80,6 +80,7 @@ public abstract class AbstractSelect< private SpanElement placeHolderElement; private InputElement inputElement; private InputElement typingElement; + private int typeAheadDelay = -1; /** * Default constructor which initializes the underlying structures, sets up event listeners, and @@ -103,7 +104,7 @@ public AbstractSelect() { .setTabIndex(-1) .onKeyPress(keyEvents -> keyEvents.alphanumeric(Event::stopPropagation))); - DelayedTextInput.create(typingElement, 1000) + DelayedTextInput.create(typingElement, getTypeAheadDelay()) .setDelayedAction( () -> { optionsMenu @@ -209,6 +210,17 @@ public AbstractSelect() { }))); } + private int getTypeAheadDelay() { + return typeAheadDelay > 0 + ? typeAheadDelay + : config().getUIConfig().getSelectBoxTypeAheadDelay(); + } + + public C setTypeAheadDelay(int delay) { + this.typeAheadDelay = delay; + return (C) this; + } + /** * Opens the options menu allowing user to select an option, unless the select is read-only or * disabled. diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSuggestBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSuggestBox.java index a08f26129..70dfa0797 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSuggestBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/AbstractSuggestBox.java @@ -27,6 +27,7 @@ import java.util.Optional; import jsinterop.base.Js; import org.dominokit.domino.ui.IsElement; +import org.dominokit.domino.ui.config.DelayedActionConfig; import org.dominokit.domino.ui.elements.DivElement; import org.dominokit.domino.ui.elements.InputElement; import org.dominokit.domino.ui.forms.AbstractFormElement; @@ -110,7 +111,7 @@ public abstract class AbstractSuggestBox< private boolean autoSelect = true; /** The type-ahead delay in milliseconds. */ - private int typeAheadDelay = 1000; + private int typeAheadDelay = -1; /** * Creates an instance of {@code AbstractSuggestBox} with the specified suggestions store. @@ -263,12 +264,16 @@ public C setAutoSelect(boolean autoSelect) { } /** - * Gets the type-ahead delay in milliseconds. + * Gets the type-ahead delay in milliseconds; this will return the value specified using {@link + * AbstractSuggestBox#setTypeAheadDelay(int)} if greater than 0 otherwise, this will return the + * value specified in {@link DelayedActionConfig#getSuggestBoxTypeAheadDelay()}. * * @return The type-ahead delay in milliseconds. */ public int getTypeAheadDelay() { - return typeAheadDelay; + return typeAheadDelay > 0 + ? typeAheadDelay + : config().getUIConfig().getSuggestBoxTypeAheadDelay(); } /** diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/CalendarLabels.java b/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/CalendarLabels.java index d26ac5508..15d900098 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/CalendarLabels.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/CalendarLabels.java @@ -29,4 +29,13 @@ public interface CalendarLabels extends Labels { default String calendarInvalidDateFormat() { return "Invalid date format"; } + /** + * Returns the localized label for the "Invalid date format" message related to calendar input. + * + * @param value the current invalid value + * @return The localized label for "Invalid date format". + */ + default String calendarInvalidDateFormat(String value) { + return calendarInvalidDateFormat() + " : " + value; + } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/TimePickerLabels.java b/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/TimePickerLabels.java index 6a2f8bb95..102670882 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/TimePickerLabels.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/TimePickerLabels.java @@ -75,4 +75,14 @@ default String ampm() { default String timePickerInvalidTimeFormat() { return "Invalid time format"; } + + /** + * Gets the error message for an invalid time format in the time picker. + * + * @param value the current invalid value + * @return The error message for an invalid time format. + */ + default String timePickerInvalidTimeFormat(String value) { + return timePickerInvalidTimeFormat() + " : " + value; + } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/notifications/Notification.java b/domino-ui/src/main/java/org/dominokit/domino/ui/notifications/Notification.java index ae382c713..c1a4c37b2 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/notifications/Notification.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/notifications/Notification.java @@ -55,7 +55,7 @@ public class Notification extends BaseDominoElement messageSpan; private final LazyChild closeButton; - private int duration = 4000; + private int duration = -1; private Transition inTransition = Transition.FADE_IN; private Transition outTransition = Transition.FADE_OUT; private SwapCssClass position = SwapCssClass.of(dui_ntf_top_left); @@ -277,13 +277,19 @@ public Notification expand() { .callback( e -> { if (!infinite) { - close(duration); + close(getDuration()); } }) .animate(); return this; } + private int getDuration() { + return this.duration > 0 + ? this.duration + : config().getUIConfig().getDefaultNotificationDuration(); + } + /** Closes the notification immediately. */ public final void close() { close(0); diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/search/SearchBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/search/SearchBox.java index 04f2bc04b..9c91863a5 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/search/SearchBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/search/SearchBox.java @@ -71,7 +71,7 @@ public class SearchBox extends BaseDominoElement implements HasLabels, HasComponentConfig { - private int autoSearchDelay; + private int autoSearchDelay = -1; private DivElement root; private final TextBox textBox; private boolean autoSearch = true; @@ -94,7 +94,7 @@ public static SearchBox create() { /** Constructs a new `SearchBox` instance with default settings. */ public SearchBox() { init(this); - this.autoSearchDelay = getConfig().getAutoSearchDelay(); + root = div().addCss(dui_quick_search); searchIcon = Icons.magnify() @@ -152,7 +152,7 @@ public void run() { autoSearchEventListener = evt -> { autoSearchTimer.cancel(); - autoSearchTimer.schedule(autoSearchDelay); + autoSearchTimer.schedule(getAutoSearchDelay()); }; setAutoSearch(true); @@ -224,7 +224,7 @@ public SearchBox setAutoSearch(boolean autoSearch) { * @return The auto search delay. */ public int getAutoSearchDelay() { - return autoSearchDelay; + return this.autoSearchDelay > 0 ? this.autoSearchDelay : getConfig().getAutoSearchDelay(); } /** diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedExecution.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedExecution.java index 6b30fd05b..71fc727b3 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedExecution.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedExecution.java @@ -15,6 +15,7 @@ */ package org.dominokit.domino.ui.utils; +import org.dominokit.domino.ui.config.DelayedActionConfig; import org.gwtproject.timer.client.Timer; /** @@ -33,6 +34,16 @@ */ public class DelayedExecution { + /** + * Executes the specified {@code delayedAction} after the specified delay defined in {@link + * DelayedActionConfig#getDelayedExecutionDefaultDelay()}. + * + * @param delayedAction The action to be executed after the delay. + */ + public static void execute(DelayedAction delayedAction) { + execute(delayedAction, DominoUIConfig.CONFIG.getUIConfig().getDelayedExecutionDefaultDelay()); + } + /** * Executes the specified {@code delayedAction} after the specified {@code delay} in milliseconds. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedTextInput.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedTextInput.java index f21244c57..0bfade70f 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedTextInput.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/DelayedTextInput.java @@ -60,6 +60,22 @@ public static DelayedTextInput create( return new DelayedTextInput(inputElement, delay, delayedAction); } + /** + * Creates a {@code DelayedTextInput} instance for the given HTML input element with a default + * delay and an action to execute on text input changes. + * + * @param inputElement The HTML input element to monitor for text input changes. + * @param delayedAction The action to execute when text input changes after the specified delay. + * @return A {@code DelayedTextInput} instance. + */ + public static DelayedTextInput create( + HTMLInputElement inputElement, DelayedAction delayedAction) { + return new DelayedTextInput( + inputElement, + DominoUIConfig.CONFIG.getUIConfig().getDelayedExecutionDefaultDelay(), + delayedAction); + } + /** * Creates a {@code DelayedTextInput} instance for the given HTML input element with a specified * delay. @@ -72,6 +88,18 @@ public static DelayedTextInput create(HTMLInputElement inputElement, int delay) return new DelayedTextInput(inputElement, delay); } + /** + * Creates a {@code DelayedTextInput} instance for the given HTML input element with a default + * delay. + * + * @param inputElement The HTML input element to monitor for text input changes. + * @return A {@code DelayedTextInput} instance. + */ + public static DelayedTextInput create(HTMLInputElement inputElement) { + return new DelayedTextInput( + inputElement, DominoUIConfig.CONFIG.getUIConfig().getDelayedExecutionDefaultDelay()); + } + /** * Creates a {@code DelayedTextInput} instance for the given DominoElement with a specified delay. * @@ -84,6 +112,19 @@ public static DelayedTextInput create(DominoElement inputEleme return create(inputElement.element(), delay); } + /** + * Creates a {@code DelayedTextInput} instance for the given DominoElement with a default delay. + * + * @param inputElement The DominoElement wrapping the HTML input element to monitor for text input + * changes. + * @return A {@code DelayedTextInput} instance. + */ + public static DelayedTextInput create(DominoElement inputElement) { + return create( + inputElement.element(), + DominoUIConfig.CONFIG.getUIConfig().getDelayedExecutionDefaultDelay()); + } + /** * Creates a {@code DelayedTextInput} instance for the given InputElement with a specified delay. * @@ -96,6 +137,19 @@ public static DelayedTextInput create(InputElement inputElement, int delay) { return create(inputElement.element(), delay); } + /** + * Creates a {@code DelayedTextInput} instance for the given InputElement with a default delay. + * + * @param inputElement The DominoElement wrapping the HTML input element to monitor for text input + * changes. + * @return A {@code DelayedTextInput} instance. + */ + public static DelayedTextInput create(InputElement inputElement) { + return create( + inputElement.element(), + DominoUIConfig.CONFIG.getUIConfig().getDelayedExecutionDefaultDelay()); + } + /** * Constructs a {@code DelayedTextInput} instance for the given HTML input element with a * specified delay.