From a18875e7cf4dd0faabff6a71e4e33c04fb8b669d Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 11 Nov 2024 13:15:45 +0300 Subject: [PATCH] fix #972 Text of selected option in a Select can be manipulated/overlayed by just typing when navigating with the tab key --- .../ui/forms/suggest/AbstractSelect.java | 6 ++++ .../domino/ui/forms/suggest/MultiSelect.java | 12 +++++++ .../domino/ui/forms/suggest/Select.java | 19 +++++++++++ .../domino/ui/keyboard/HasKeyboardEvents.java | 15 +++++++++ .../domino/ui/keyboard/KeyboardEvents.java | 32 +++++++++++++++++-- .../domino/ui/utils/BaseDominoElement.java | 25 +++++++++++++++ 6 files changed, 107 insertions(+), 2 deletions(-) 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 96d25e4b8..3ba797d51 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 @@ -100,6 +100,7 @@ public AbstractSelect() { .appendChild( typingElement = input("text") + .addEventListener("input", evt -> onTypingStart()) .addCss(dui_auto_type_input, dui_hidden) .setTabIndex(-1) .onKeyPress(keyEvents -> keyEvents.alphanumeric(Event::stopPropagation))); @@ -115,6 +116,7 @@ public AbstractSelect() { optionsMenu.focusFirstMatch(typingElement.getValue()); typingElement.setValue(null).addCss(dui_hidden); focus(); + onTypingEnd(); }) .setOnEnterAction( () -> { @@ -212,6 +214,10 @@ public AbstractSelect() { }))); } + protected abstract void onTypingStart(); + + protected abstract void onTypingEnd(); + private int getTypeAheadDelay() { return typeAheadDelay > 0 ? typeAheadDelay diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSelect.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSelect.java index 0397f9ba6..2fa663e5b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSelect.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSelect.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.dominokit.domino.ui.elements.DivElement; +import org.dominokit.domino.ui.utils.BaseDominoElement; /** * Represents a multi-selection dropdown menu UI component, allowing users to select multiple @@ -157,6 +158,7 @@ protected void onOptionSelected(SelectOption option, boolean silent) { } withOption(option, silent); updateTextValue(); + option.addCss(() -> "dui-selected-option"); fieldInput.appendChild(option); selectedOptions.add(option); getInputElement().element().focus(); @@ -225,4 +227,14 @@ protected void doSetOption(SelectOption option) { public List getValue() { return this.selectedOptions.stream().map(Option::getValue).collect(Collectors.toList()); } + + @Override + protected void onTypingStart() { + this.selectedOptions.forEach(BaseDominoElement::hide); + } + + @Override + protected void onTypingEnd() { + this.selectedOptions.forEach(BaseDominoElement::show); + } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/Select.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/Select.java index 0bc216116..ef0195c4c 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/Select.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/Select.java @@ -18,9 +18,11 @@ import static java.util.Objects.isNull; import static java.util.Objects.nonNull; +import elemental2.dom.DomGlobal; import java.util.Objects; import java.util.Optional; import org.dominokit.domino.ui.elements.DivElement; +import org.dominokit.domino.ui.utils.BaseDominoElement; /** * Represents a dropdown select control allowing the user to choose a single option from a list. @@ -84,6 +86,22 @@ protected void doSetValue(V value, boolean silent) { } } + @Override + protected void onTypingStart() { + DomGlobal.console.info("Typing typing typing -----"); + Optional.ofNullable(selectedOption) + .ifPresent( + vSelectOption -> { + DomGlobal.console.info("Hide Hide Hide -----"); + vSelectOption.hide(); + }); + } + + @Override + protected void onTypingEnd() { + Optional.ofNullable(selectedOption).ifPresent(BaseDominoElement::show); + } + @Override protected Select clearValue(boolean silent) { Select thisSelect = super.clearValue(silent); @@ -125,6 +143,7 @@ public Select withOption(SelectOption option, boolean silent) { updateTextValue(); this.selectedOption = option; + option.addCss(() -> "dui-selected-option"); fieldInput.appendChild(option); if (!silent) { diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/HasKeyboardEvents.java b/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/HasKeyboardEvents.java index b94345389..8a6ab46f9 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/HasKeyboardEvents.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/HasKeyboardEvents.java @@ -68,6 +68,21 @@ public interface HasKeyboardEvents { */ T stopOnKeyPress(); + /** + * Registers an event listener to be called when an input is applied. + * + * @param onInput The {@link KeyEventsConsumer} to call when an input is applied. + * @return The instance of type {@code T} for method chaining. + */ + T onInput(KeyEventsConsumer onInput); + + /** + * Stops listening for input events. + * + * @return The instance of type {@code T} for method chaining. + */ + T stopOnInput(); + /** * Gets the keyboard event options associated with this instance. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/KeyboardEvents.java b/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/KeyboardEvents.java index d9913005a..44cb8c66d 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/KeyboardEvents.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/keyboard/KeyboardEvents.java @@ -15,8 +15,6 @@ */ package org.dominokit.domino.ui.keyboard; -import static org.dominokit.domino.ui.utils.Domino.*; - import elemental2.dom.Node; import org.dominokit.domino.ui.events.HasDefaultEventOptions; import org.dominokit.domino.ui.utils.LazyInitializer; @@ -44,16 +42,20 @@ public class KeyboardEvents /** The constant representing the "keypress" event type. */ public static final String KEYPRESS = "keypress"; + public static final String INPUT = "input"; + private KeyboardEventOptions defaultOptions = KeyboardEventOptions.create(); private final T element; private KeyboardKeyListener keyUpListener = new KeyboardKeyListener(this); private KeyboardKeyListener keyDownListener = new KeyboardKeyListener(this); private KeyboardKeyListener keyPressListener = new KeyboardKeyListener(this); + private KeyboardKeyListener inputListener = new KeyboardKeyListener(this); private LazyInitializer keyUpListenerInitializer; private LazyInitializer keyDownListenerInitializer; private LazyInitializer keyPressListenerInitializer; + private LazyInitializer InputListenerInitializer; /** * Creates a new instance of {@code KeyboardEvents} for the specified DOM element. @@ -68,6 +70,8 @@ public KeyboardEvents(T element) { new LazyInitializer(() -> element.addEventListener(KEYDOWN, keyDownListener)); keyPressListenerInitializer = new LazyInitializer(() -> element.addEventListener(KEYPRESS, keyPressListener)); + InputListenerInitializer = + new LazyInitializer(() -> element.addEventListener(INPUT, inputListener)); } /** @@ -142,6 +146,30 @@ public KeyboardEvents stopListenOnKeyPress() { return this; } + /** + * Adds a keypress event listener to the element and associates it with the provided {@code + * onInput} consumer. + * + * @param onInput The consumer that will receive keypress events. + * @return This {@code KeyboardEvents} instance for method chaining. + */ + public KeyboardEvents listenOnInput(KeyEventsConsumer onInput) { + InputListenerInitializer.apply(); + onInput.accept(inputListener); + return this; + } + + /** + * Removes the keypress event listener from the element. + * + * @return This {@code KeyboardEvents} instance for method chaining. + */ + public KeyboardEvents stopListenOnInput() { + element.removeEventListener(INPUT, inputListener); + InputListenerInitializer.reset(); + return this; + } + /** {@inheritDoc} */ @Override public KeyboardEventOptions getOptions() { diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java index 3f4ef5e99..5289a26d1 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BaseDominoElement.java @@ -4144,6 +4144,31 @@ public T stopOnKeyPress() { return (T) this; } + /** + * Registers an event handler to be executed when a key is pressed and released. + * + * @param onInput The event handler for key press events. + * @return The modified DOM element. + */ + @Override + public T onInput(KeyEventsConsumer onInput) { + keyEventsInitializer.apply(); + keyboardEvents.listenOnInput(onInput); + return (T) this; + } + + /** + * Stops listening to key press events. + * + * @return The modified DOM element. + */ + @Override + public T stopOnInput() { + keyEventsInitializer.apply(); + keyboardEvents.stopListenOnInput(); + return (T) this; + } + /** * Retrieves the options for keyboard events. *