From af70269dc88e034733bbbd8280821598d2d15682 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Fri, 10 May 2024 22:56:55 +0300 Subject: [PATCH 01/21] Update for next development version --- domino-ui-shared/pom.xml | 2 +- domino-ui-tools/mdi-icons-processor/pom.xml | 2 +- domino-ui-tools/pom.xml | 2 +- domino-ui-webjar/pom.xml | 2 +- domino-ui/pom.xml | 2 +- pom.xml | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/domino-ui-shared/pom.xml b/domino-ui-shared/pom.xml index 8dabbb838..1f341d698 100644 --- a/domino-ui-shared/pom.xml +++ b/domino-ui-shared/pom.xml @@ -5,7 +5,7 @@ domino-ui-parent org.dominokit - 2.0.1 + HEAD-SNAPSHOT jar 4.0.0 diff --git a/domino-ui-tools/mdi-icons-processor/pom.xml b/domino-ui-tools/mdi-icons-processor/pom.xml index e2e7801ef..178f2d8e9 100644 --- a/domino-ui-tools/mdi-icons-processor/pom.xml +++ b/domino-ui-tools/mdi-icons-processor/pom.xml @@ -5,7 +5,7 @@ domino-ui-tools org.dominokit - 2.0.1 + HEAD-SNAPSHOT 4.0.0 diff --git a/domino-ui-tools/pom.xml b/domino-ui-tools/pom.xml index 1d008ed76..83024dce5 100644 --- a/domino-ui-tools/pom.xml +++ b/domino-ui-tools/pom.xml @@ -5,7 +5,7 @@ domino-ui-parent org.dominokit - 2.0.1 + HEAD-SNAPSHOT 4.0.0 diff --git a/domino-ui-webjar/pom.xml b/domino-ui-webjar/pom.xml index 2e5972d55..6485a5624 100644 --- a/domino-ui-webjar/pom.xml +++ b/domino-ui-webjar/pom.xml @@ -5,7 +5,7 @@ domino-ui-parent org.dominokit - 2.0.1 + HEAD-SNAPSHOT jar 4.0.0 diff --git a/domino-ui/pom.xml b/domino-ui/pom.xml index d9b77dbee..ef01cc082 100644 --- a/domino-ui/pom.xml +++ b/domino-ui/pom.xml @@ -6,7 +6,7 @@ org.dominokit domino-ui-parent - 2.0.1 + HEAD-SNAPSHOT domino-ui diff --git a/pom.xml b/pom.xml index a0bd89b7f..9c2d61604 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.dominokit domino-ui-parent - 2.0.1 + HEAD-SNAPSHOT pom domino-ui-parent @@ -68,7 +68,7 @@ HEAD-SNAPSHOT - 2.0.1 + 2.0.2 11 11 From c8aefa1c7673c4375a8b3fe22fcc496fc007de10 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Wed, 26 Jun 2024 14:48:03 +0300 Subject: [PATCH 02/21] minor enhancements --- .../domino/ui/elements/ImageElement.java | 11 +++ .../org/dominokit/domino/ui/forms/Radio.java | 1 - .../domino/ui/icons/LabeledIcon.java | 52 +++++++++++++- .../domino/ui/utils/BodyObserver.java | 71 +++++++++++-------- .../dominokit/domino/ui/utils/Clipboard.java | 23 ++++++ 5 files changed, 127 insertions(+), 31 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/elements/ImageElement.java b/domino-ui/src/main/java/org/dominokit/domino/ui/elements/ImageElement.java index 0231ea4fe..6db5ed674 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/elements/ImageElement.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/elements/ImageElement.java @@ -54,4 +54,15 @@ public static ImageElement of(HTMLImageElement e) { public ImageElement(HTMLImageElement element) { super(element); } + + /** + * Sets the src for the image element + * + * @param src String image source + * @return same component + */ + public ImageElement src(String src) { + setAttribute("src", src); + return this; + } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/Radio.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/Radio.java index beb23542f..d0b807525 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/Radio.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/Radio.java @@ -101,7 +101,6 @@ public Radio(T value, String label) { inputElement.addEventListener( "change", evt -> { - DomGlobal.console.info("CHANGEEEEEEEED.!"); if (isEnabled() && !isReadOnly()) { setChecked(isChecked(), isChangeListenersPaused()); } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/icons/LabeledIcon.java b/domino-ui/src/main/java/org/dominokit/domino/ui/icons/LabeledIcon.java index b2ab41d13..44e615325 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/icons/LabeledIcon.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/icons/LabeledIcon.java @@ -22,6 +22,7 @@ import elemental2.dom.HTMLElement; import org.dominokit.domino.ui.elements.SpanElement; import org.dominokit.domino.ui.style.WavesElement; +import org.dominokit.domino.ui.utils.ChildHandler; /** * A component that combines an icon and a text label, allowing you to create labeled icons with @@ -30,6 +31,8 @@ public class LabeledIcon extends WavesElement { private final SpanElement element; + private final SpanElement textElement; + private final Icon icon; /** * Creates a labeled icon with the provided icon and text, positioned to the left. @@ -52,8 +55,9 @@ public LabeledIcon(Icon icon, String text, IconPosition position) { element = span() .addCss(dui_labeled_icon) - .appendChild(icon) - .appendChild(span().addCss(dui_icon_text, dui_text_ellipsis).textContent(text)); + .appendChild(this.icon = icon) + .appendChild( + textElement = span().addCss(dui_icon_text, dui_text_ellipsis).textContent(text)); init(this); position.apply(this); } @@ -82,6 +86,50 @@ public static LabeledIcon create(Icon icon, String text, IconPosition positio return new LabeledIcon(icon, text, position); } + /** + * Changes the text of the labeled icon + * + * @param text the new text. + * @return same component + */ + public LabeledIcon setText(String text) { + this.textElement.setTextContent(text); + return this; + } + + /** + * Apply a handler to the labeledIcon text element. + * + * @param handler the handler to be applied + * @return same component + */ + public LabeledIcon withTextElement(ChildHandler handler) { + handler.apply(this, textElement); + return this; + } + + /** + * Apply a handler to the labeledIcon icon element. + * + * @param handler the handler to be applied + * @return same component + */ + public LabeledIcon withIcon(ChildHandler> handler) { + handler.apply(this, icon); + return this; + } + + /** + * Applies a new position for the labeledIcon text. + * + * @param position The new position to be applied + * @return same component. + */ + public LabeledIcon setIconPosition(IconPosition position) { + position.apply(this); + return this; + } + /** @dominokit-site-ignore {@inheritDoc} */ @Override public HTMLElement element() { diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BodyObserver.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BodyObserver.java index f4b195222..e3479b497 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BodyObserver.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/BodyObserver.java @@ -24,13 +24,16 @@ import elemental2.core.JsArray; import elemental2.dom.CustomEvent; import elemental2.dom.CustomEventInit; +import elemental2.dom.Element; import elemental2.dom.Event; import elemental2.dom.HTMLElement; import elemental2.dom.MutationObserver; import elemental2.dom.MutationObserverInit; import elemental2.dom.MutationRecord; import elemental2.dom.Node; +import java.util.HashSet; import java.util.List; +import java.util.Set; import jsinterop.base.Js; /** @@ -96,52 +99,64 @@ private static void observe() { private static void onElementsAppended(MutationRecord record) { List nodes = record.addedNodes.asList(); + Set processed = new HashSet<>(); for (int i = 0; i < nodes.size(); i++) { Node elementNode = Js.uncheckedCast(nodes.get(i)); if (Node.ELEMENT_NODE == elementNode.nodeType) { HTMLElement element = Js.uncheckedCast(elementNode); + List> childElements = + elements.elementOf(element).querySelectorAll("[" + ATTACH_UID_KEY + "]"); if (element.hasAttribute(ATTACH_UID_KEY)) { - element.dispatchEvent( - new CustomEvent<>(AttachDetachEventType.attachedType(elements.elementOf(element)))); + String type = AttachDetachEventType.attachedType(elements.elementOf(element)); + if (!processed.contains(type)) { + processed.add(type); + element.dispatchEvent(new CustomEvent<>(type)); + } } - elements - .elementOf(element) - .querySelectorAll("[" + ATTACH_UID_KEY + "]") - .forEach( - child -> { - CustomEventInit ceinit = CustomEventInit.create(); - ceinit.setDetail(record); - CustomEvent event = - new CustomEvent<>( - AttachDetachEventType.attachedType(elements.elementOf(child)), ceinit); - child.element().dispatchEvent(event); - }); + + childElements.forEach( + child -> { + CustomEventInit ceinit = CustomEventInit.create(); + ceinit.setDetail(record); + String type = AttachDetachEventType.attachedType(elements.elementOf(child)); + if (!processed.contains(type)) { + processed.add(type); + CustomEvent event = new CustomEvent<>(type, ceinit); + child.element().dispatchEvent(event); + } + }); } } } private static void onElementsRemoved(MutationRecord record) { List nodes = record.removedNodes.asList(); + Set processed = new HashSet<>(); for (int i = 0; i < nodes.size(); i++) { Node elementNode = Js.uncheckedCast(nodes.get(i)); if (Node.ELEMENT_NODE == elementNode.nodeType) { HTMLElement element = Js.uncheckedCast(elementNode); + List> childElements = + elements.elementOf(element).querySelectorAll("[" + DETACH_UID_KEY + "]"); if (element.hasAttribute(DETACH_UID_KEY)) { - element.dispatchEvent( - new Event(AttachDetachEventType.detachedType(elements.elementOf(element)))); + String type = AttachDetachEventType.detachedType(elements.elementOf(element)); + if (!processed.contains(type)) { + processed.add(type); + element.dispatchEvent(new Event(type)); + } } - elements - .elementOf(element) - .querySelectorAll("[" + DETACH_UID_KEY + "]") - .forEach( - child -> { - CustomEventInit ceinit = CustomEventInit.create(); - ceinit.setDetail(record); - CustomEvent event = - new CustomEvent<>( - AttachDetachEventType.detachedType(elements.elementOf(child)), ceinit); - child.element().dispatchEvent(event); - }); + + childElements.forEach( + child -> { + String type = AttachDetachEventType.detachedType(elements.elementOf(child)); + if (!processed.contains(type)) { + processed.add(type); + CustomEventInit ceinit = CustomEventInit.create(); + ceinit.setDetail(record); + CustomEvent event = new CustomEvent<>(type, ceinit); + child.element().dispatchEvent(event); + } + }); } } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/Clipboard.java b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/Clipboard.java index 4b716e44d..04045061d 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/utils/Clipboard.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/utils/Clipboard.java @@ -16,10 +16,13 @@ package org.dominokit.domino.ui.utils; import elemental2.core.JsArray; +import elemental2.dom.DomGlobal; import elemental2.promise.Promise; +import jsinterop.annotations.JsOverlay; import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; import jsinterop.base.Any; +import jsinterop.base.Js; /** * A class for interacting with the clipboard to read and write data. @@ -59,4 +62,24 @@ public class Clipboard { * @return A promise that resolves when the text data is successfully written to the clipboard. */ public native Promise writeText(String text); + + @JsOverlay + public static Promise> get() { + return Js.uncheckedCast(DomGlobal.window.navigator).clipboard.read(); + } + + @JsOverlay + public static Promise getText() { + return Js.uncheckedCast(DomGlobal.window.navigator).clipboard.readText(); + } + + @JsOverlay + public static Promise put(ClipboardItem item) { + return Js.uncheckedCast(DomGlobal.window.navigator).clipboard.write(item); + } + + @JsOverlay + public static Promise put(String text) { + return Js.uncheckedCast(DomGlobal.window.navigator).clipboard.writeText(text); + } } From fbcbb51469cc91d71c4888c072ae217b91fe441e Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Sun, 14 Jul 2024 17:21:45 +0300 Subject: [PATCH 03/21] fix #936 datetime box/picker enhancements, more delayed actions configurations --- .../domino/ui/config/DelayedActionConfig.java | 48 +++++++++++++++++ .../domino/ui/config/SearchConfig.java | 4 +- .../dominokit/domino/ui/config/UIConfig.java | 3 +- .../domino/ui/datepicker/Calendar.java | 21 +++++--- .../dominokit/domino/ui/forms/DateBox.java | 27 +++++++++- .../dominokit/domino/ui/forms/TimeBox.java | 2 +- .../ui/forms/suggest/AbstractSelect.java | 14 ++++- .../ui/forms/suggest/AbstractSuggestBox.java | 11 ++-- .../domino/ui/i18n/CalendarLabels.java | 9 ++++ .../domino/ui/i18n/TimePickerLabels.java | 10 ++++ .../domino/ui/notifications/Notification.java | 10 +++- .../dominokit/domino/ui/search/SearchBox.java | 8 +-- .../domino/ui/utils/DelayedExecution.java | 11 ++++ .../domino/ui/utils/DelayedTextInput.java | 54 +++++++++++++++++++ 14 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/config/DelayedActionConfig.java 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. From 1065c23046eea34f7a40d03006aca8cda6b00bed Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Sun, 14 Jul 2024 18:29:51 +0300 Subject: [PATCH 04/21] fix #932 Wrong UI interaction between datatable SummaryPlugin and EmptyStatePlugin --- .../domino/ui/datatable/TableConfig.java | 9 +++++ .../plugins/summary/EmptyStatePlugin.java | 38 +++++++++++++++++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/TableConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/TableConfig.java index 43a42c643..cd1753291 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/TableConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/TableConfig.java @@ -390,6 +390,15 @@ public List> getFlattenColumns() { .collect(Collectors.toList()); } + /** + * Retrieves only the leaf columns of the data table. + * + * @return A list of {@link ColumnConfig} representing all columns, flattened. + */ + public List> getLeafColumns() { + return columns.stream().flatMap(col -> col.leafColumns().stream()).collect(Collectors.toList()); + } + /** * Retrieves the columns of the DataTable as grouped. * diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/EmptyStatePlugin.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/EmptyStatePlugin.java index 4764fc19d..7fba6e4ad 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/EmptyStatePlugin.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/EmptyStatePlugin.java @@ -19,6 +19,9 @@ import org.dominokit.domino.ui.datatable.DataTable; import org.dominokit.domino.ui.datatable.events.TableDataUpdatedEvent; import org.dominokit.domino.ui.datatable.plugins.DataTablePlugin; +import org.dominokit.domino.ui.elements.TDElement; +import org.dominokit.domino.ui.elements.TFootElement; +import org.dominokit.domino.ui.elements.TableRowElement; import org.dominokit.domino.ui.icons.Icon; import org.dominokit.domino.ui.layout.EmptyState; import org.dominokit.domino.ui.utils.ChildHandler; @@ -47,6 +50,9 @@ public class EmptyStatePlugin implements DataTablePlugin { private EmptyState emptyState; + private TableRowElement rowElement = tr(); + private TDElement stateCell = td(); + private TFootElement footer; /** * Creates and returns a new instance of {@code EmptyStatePlugin} with the provided icon and @@ -72,18 +78,42 @@ public EmptyStatePlugin(Icon emptyStateIcon, String title) { } @Override - public void onAfterAddTable(DataTable dataTable) { + public void init(DataTable dataTable) { + rowElement + .addCss(dui_table_row) + .appendChild(stateCell.addCss(dui_table_cell).appendChild(emptyState)); + } + + /** + * Invoked when the footer is added to the DataTable. + * + * @param datatable The DataTable to which the footer is added. + */ + @Override + public void onFooterAdded(DataTable datatable) { + this.footer = datatable.footerElement(); + this.footer.appendChild(rowElement); + } + + @Override + public void onAfterAddTable(DataTable dataTable) { dataTable.addTableEventListener( TableDataUpdatedEvent.DATA_UPDATED, event -> { TableDataUpdatedEvent tableDataUpdatedEvent = (TableDataUpdatedEvent) event; + long columnsCount = + dataTable.getTableConfig().getLeafColumns().stream() + .filter(c -> !c.isHidden()) + .count(); + stateCell.setAttribute("colspan", columnsCount); + if (tableDataUpdatedEvent.getTotalCount() == 0) { - emptyState.show(); + rowElement.show(); } else { - emptyState.hide(); + rowElement.hide(); } }); - dataTable.element().appendChild(emptyState.element()); + this.footer.insertFirst(rowElement); } /** From 70056a87d4af5f84d893a264e018b8472eaf5b43 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 00:58:59 +0300 Subject: [PATCH 05/21] fix #934 change listeners not fired when SuggestBox cleared from keyboard --- .../domino/ui/forms/suggest/AbstractSuggestBox.java | 10 +++++++++- .../domino/ui/forms/suggest/MultiSuggestBox.java | 1 - .../domino/ui/forms/suggest/SuggestBox.java | 13 ++++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) 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 70dfa0797..5808c46c7 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 @@ -176,7 +176,7 @@ public AbstractSuggestBox(SuggestionsStore store) { }))); getInputElement() - .onKeyDown( + .onKeyUp( keyEvents -> { keyEvents .onArrowDown( @@ -224,6 +224,14 @@ public AbstractSuggestBox(SuggestionsStore store) { onBackspace(); } } + }) + .onDelete( + evt -> { + if (!isReadOnly() && !isDisabled()) { + evt.stopPropagation(); + evt.preventDefault(); + onBackspace(); + } }); }); } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSuggestBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSuggestBox.java index cb079cb5f..0b1ef30b9 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSuggestBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/MultiSuggestBox.java @@ -116,7 +116,6 @@ public void onOptionSelected(O option) { } withOption(option); fieldInput.appendChild(option); - selectedOptions.add(option); option.bindTo(this); } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java index 658632ba0..626621ea2 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java @@ -101,10 +101,7 @@ public V getValue() { /** Handles the "Backspace" key event. */ @Override protected void onBackspace() { - if (nonNull(selectedOption)) { - selectedOption.remove(); - selectedOption = null; - } + clearValue(isChangeListenersPaused()); } /** @@ -164,6 +161,7 @@ private void updateTextValue() { @Override public void onOptionDeselected(O option) { option.remove(); + V oldValue = this.selectedOption.getValue(); if (Objects.equals(this.selectedOption, option)) { this.selectedOption = null; } @@ -184,7 +182,12 @@ public void onOptionDeselected(O option) { protected SuggestBox clearValue(boolean silent) { if (nonNull(selectedOption)) { V oldValue = getValue(); - withPauseChangeListenersToggle(true, field -> onOptionDeselected(selectedOption)); + withPauseChangeListenersToggle( + true, + field -> { + onOptionDeselected(selectedOption); + getInputElement().element().value = null; + }); if (!silent) { triggerClearListeners(oldValue); From 65bad2170a4672d10302a19baba93ab802d49335 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 01:16:55 +0300 Subject: [PATCH 06/21] fix #935 expose some members from AbstractSuggestBox class --- .../domino/ui/config/DelayedActionConfig.java | 29 +++++++++++++++ .../ui/forms/suggest/AbstractSuggestBox.java | 35 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) 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 index 04bcd5b3e..4653b86b7 100644 --- 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 @@ -26,22 +26,51 @@ default int getDelayedExecutionDefaultDelay() { return 200; } + /** + * Use to globally configure select/suggest box search box typeahead delay. + * + * @return the delay in milliseconds, default to 1000ms + */ default int getDefaultSelectableBoxTypeAheadDelay() { return 1000; } + /** + * Use to globally configure Suggest box search box typeahead delay. + * + * @return the delay in milliseconds, default to {@link + * DelayedActionConfig#getDefaultSelectableBoxTypeAheadDelay()} + */ default int getSuggestBoxTypeAheadDelay() { return getDefaultSelectableBoxTypeAheadDelay(); } + /** + * Use to globally configure Select box search box typeahead delay. + * + * @return the delay in milliseconds, default to {@link + * DelayedActionConfig#getDefaultSelectableBoxTypeAheadDelay()} + */ default int getSelectBoxTypeAheadDelay() { return getDefaultSelectableBoxTypeAheadDelay(); } + /** + * Use to globally configure notification duration. + * + * @return the delay in milliseconds, default to 4000ms. + */ default int getDefaultNotificationDuration() { return 4000; } + /** + * Use to globally configure the delay before a datebox start parsing the value while tying in the + * date box input. + * + * @return the delay in milliseconds, default to {@link + * DelayedActionConfig#getDelayedExecutionDefaultDelay()}. + */ default int getDateBoxDefaultInputParseDelay() { return getDelayedExecutionDefaultDelay(); } 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 5808c46c7..3b5d83c91 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 @@ -299,7 +299,7 @@ public void setTypeAheadDelay(int typeAheadDelayInMillis) { * the suggestions from the store, highlighting the matched portions, and updating the options * menu. */ - private void search() { + protected void search() { if (store != null) { loader.start(); optionsMenu.removeAll(); @@ -716,6 +716,39 @@ public C withOptionsMenu(ChildHandler> handler) { return (C) this; } + /** + * Use to change the default search loader of a suggest box. + * + * @param loader + * @return same component instance + */ + public C setLoader(Loader loader) { + this.loader = loader; + return (C) this; + } + + /** + * Use to apply a function on search loader of a suggest box. + * + * @param handler + * @return same component instance + */ + public C withLoader(ChildHandler handler) { + handler.apply((C) this, loader); + return (C) this; + } + + /** + * Use to apply a function on element hosting the suggest box search loader. + * + * @param handler + * @return same component instance + */ + public C withLoaderElement(ChildHandler> handler) { + handler.apply((C) this, loaderElement); + return (C) this; + } + /** * An interface for rendering the value of a suggestion option in a suggest box. * From 701b7c97b5c8bbe8b83259e287547cc09630cc70 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 01:28:19 +0300 Subject: [PATCH 07/21] fix #937 Select loses focus after selection --- .../java/org/dominokit/domino/ui/forms/suggest/MultiSelect.java | 1 + .../main/java/org/dominokit/domino/ui/forms/suggest/Select.java | 1 + 2 files changed, 2 insertions(+) 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 4442aef7b..267d88ae2 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 @@ -154,6 +154,7 @@ protected void onOptionSelected(SelectOption option, boolean silent) { updateTextValue(); fieldInput.appendChild(option); selectedOptions.add(option); + getInputElement().element().focus(); } /** 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 3c8e2f0c2..956fb3862 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 @@ -118,6 +118,7 @@ public Select withOption(SelectOption option, boolean silent) { } } autoValidate(); + getInputElement().element().focus(); return this; } From 965e95efad7db2e147c96468364c43d143609d2a Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 01:43:53 +0300 Subject: [PATCH 08/21] fix #938 DataTable / Render error with PinColumnsPlugin and ColumnHeaderFilterPlugin --- .../ui/datatable/plugins/column/ColumnHeaderFilterPlugin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/column/ColumnHeaderFilterPlugin.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/column/ColumnHeaderFilterPlugin.java index 48eaa42c6..a53e394bc 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/column/ColumnHeaderFilterPlugin.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/column/ColumnHeaderFilterPlugin.java @@ -18,6 +18,7 @@ import static java.util.Objects.nonNull; import static org.dominokit.domino.ui.datatable.DataTableStyles.dui_datatable_column_filter; +import static org.dominokit.domino.ui.datatable.DataTableStyles.dui_datatable_row; import static org.dominokit.domino.ui.utils.Domino.*; import elemental2.dom.HTMLElement; @@ -55,6 +56,7 @@ public class ColumnHeaderFilterPlugin implements DataTablePlugin { @Override public void init(DataTable dataTable) { this.datatable = dataTable; + this.filtersRowElement.addCss(dui_datatable_row); } /** From 5663ae42b442cbb4e97b29dea78bde8077426e6b Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 02:10:39 +0300 Subject: [PATCH 09/21] fix #939 calling clear value for multiselect box will repeat the call for change listener by the number of selected items. --- .../domino/ui/forms/suggest/AbstractSelect.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 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 e073e8a54..5232b5e5a 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 @@ -277,11 +277,15 @@ protected C clearValue(boolean silent) { new ArrayList<>(selection) .forEach( item -> { - item.deselect(silent); - if (silent) { - OptionMeta.get(item) - .ifPresent(meta -> onOptionDeselected((O) meta.getOption(), silent)); - } + withPausedChangeListeners( + select -> { + item.deselect(silent); + if (silent) { + OptionMeta.get(item) + .ifPresent( + meta -> onOptionDeselected((O) meta.getOption(), silent)); + } + }); }); }); From f874529c2292197a1dc745ff1c9b08dd0f3d580a Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 15:07:01 +0300 Subject: [PATCH 10/21] fix #942 FileUpload does not respect setMultiple(false) --- .../domino/ui/config/HasComponentConfig.java | 9 ++ .../domino/ui/config/UploadConfig.java | 11 +++ .../domino/ui/i18n/UploadLabels.java | 11 ++- .../upload/DefaultFilePreviewContainer.java | 14 +++- .../domino/ui/upload/FileUpload.java | 82 +++++++++++++++---- 5 files changed, 109 insertions(+), 18 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/HasComponentConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/HasComponentConfig.java index 14aa22626..6fca00de3 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/config/HasComponentConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/HasComponentConfig.java @@ -15,6 +15,8 @@ */ package org.dominokit.domino.ui.config; +import static java.util.Objects.nonNull; + import org.dominokit.domino.ui.utils.DominoUIConfig; /** HasComponentConfig interface. */ @@ -25,6 +27,13 @@ public interface HasComponentConfig { * @return a T object */ default T getConfig() { + if (nonNull(getOwnConfig())) { + return getOwnConfig(); + } return (T) DominoUIConfig.CONFIG.getUIConfig(); } + + default T getOwnConfig() { + return null; + } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/UploadConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/UploadConfig.java index 493f4f385..e3b990f17 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/config/UploadConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/UploadConfig.java @@ -81,4 +81,15 @@ default FilePreviewFactory getFilePreviewFactory() { default Supplier> getDefaultFilePreviewContainer() { return DefaultFilePreviewContainer::new; } + + /** + * when the user uploaded a set of files that are less or equals the max uploads allowed, and they + * are already uploaded, should we allow him to upload a new set of files that are in total with + * the previous batch could overflow the max allowed upload limit. + * + * @return boolean default true + */ + default boolean isMaxUploadsOverflowAllowed() { + return true; + } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/UploadLabels.java b/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/UploadLabels.java index 6e21d8c7a..3ec2b4f0a 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/UploadLabels.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/i18n/UploadLabels.java @@ -55,7 +55,14 @@ default String getDefaultUploadCanceledMessage() { * @param current The current number of uploads. * @return The error message for exceeding the maximum allowed uploads. */ - default String getMaxFileErrorMessage(int maxFiles, int current) { - return "The maximum allowed uploads is : " + maxFiles + ", You have " + current; + default String getMaxFileErrorMessage(int maxFiles, int current, int added, int ignored) { + return "The maximum allowed uploads is : " + + maxFiles + + ", You have : " + + current + + ", added : " + + added + + ", ignored : " + + ignored; } } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java index faf549d54..c22e2568b 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java @@ -17,7 +17,9 @@ import static org.dominokit.domino.ui.utils.Domino.*; +import elemental2.dom.DomGlobal; import elemental2.dom.HTMLDivElement; +import org.dominokit.domino.ui.grid.Column; import org.dominokit.domino.ui.grid.Row; import org.dominokit.domino.ui.utils.BaseDominoElement; import org.dominokit.domino.ui.utils.ChildHandler; @@ -50,7 +52,17 @@ public DefaultFilePreviewContainer() { */ @Override public DefaultFilePreviewContainer appendChild(FileItem fileItem) { - rootRow.span2(fileItem); + rootRow.appendChild( + Column.span2() + .apply( + self -> { + self.appendChild(fileItem); + fileItem.onDetached( + mutationRecord -> { + DomGlobal.console.info("delete columns too ------------------"); + self.remove(); + }); + })); return this; } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java index 3522538df..3a11a6add 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java @@ -22,6 +22,7 @@ import elemental2.dom.*; import java.util.*; import java.util.function.Supplier; +import java.util.stream.Collectors; import jsinterop.base.Js; import org.dominokit.domino.ui.IsElement; import org.dominokit.domino.ui.config.HasComponentConfig; @@ -98,6 +99,7 @@ public class FileUpload extends BaseDominoElement private UploadRequestSender requestSender = (XMLHttpRequest::send); private DropEffect dropEffect; + private UploadConfig config; /** * Creates a new instance of the `FileUpload` component. @@ -195,7 +197,7 @@ public FileUpload( elementOf(filesContainer.element()).addCss(dui_file_preview_container); init(this); root.addClickListener(evt -> hiddenFileInput.element().click()); - hiddenFileInput.addEventListener("change", evt -> uploadFiles(hiddenFileInput.element().files)); + hiddenFileInput.addEventListener("change", evt -> tryUpload(hiddenFileInput.element().files)); root.addEventListener( "drop", evt -> { @@ -210,14 +212,7 @@ public FileUpload( ((DragEvent) evt).dataTransfer.dropEffect = effect.getEffect(); } }); - int maxAllowed = hiddenFileInput.element().multiple ? maxAllowedUploads : 1; - if (maxAllowed > files.length) { - messagesContainer - .clearElement() - .setTextContent(getLabels().getMaxFileErrorMessage(maxAllowed, files.length)); - } else { - uploadFiles(files); - } + tryUpload(files); removeHover(); }); root.addEventListener( @@ -242,6 +237,37 @@ public FileUpload( }); } + private void tryUpload(FileList files) { + + int maxAllowed = isMultiUpload() ? maxAllowedUploads : 1; + int addedFiles = addedFileItems.size(); + List uploadedFiles = + addedFileItems.stream().filter(FileItem::isUploaded).collect(Collectors.toList()); + int remainingAllowed = Math.max(0, maxAllowed - (addedFiles - uploadedFiles.size())); + int existing = addedFiles - uploadedFiles.size(); + int ignored = files.length - remainingAllowed; + if (files.length > remainingAllowed) { + if (getConfig().isMaxUploadsOverflowAllowed()) { + uploadedFiles.forEach(FileItem::remove); + List toBeUploaded = files.asList().subList(0, remainingAllowed); + uploadFiles(toBeUploaded); + + messagesContainer + .clearElement() + .setTextContent( + getLabels() + .getMaxFileErrorMessage(maxAllowed, existing, remainingAllowed, ignored)); + } else { + messagesContainer + .clearElement() + .setTextContent( + getLabels().getMaxFileErrorMessage(maxAllowed, existing, 0, files.length)); + } + } else { + uploadFiles(files.asList()); + } + } + /** * Creates a new instance of the `FileUpload` component with a custom file preview factory, file * preview container, and decoration element. @@ -294,8 +320,9 @@ public FileUpload setDecoration(Element decoration) { * * @param maxAllowedUploads The maximum number of allowed uploads. */ - public void setMaxAllowedUploads(int maxAllowedUploads) { + public FileUpload setMaxAllowedUploads(int maxAllowedUploads) { this.maxAllowedUploads = maxAllowedUploads; + return this; } /** @@ -333,17 +360,29 @@ private void addHover() { * * @param files The list of files to upload. */ - public void uploadFiles(FileList files) { - for (int i = 0; i < files.length; i++) { - File file = files.item(i); + public FileUpload uploadFiles(List files) { + for (int i = 0; i < files.size(); i++) { + File file = files.get(i); addFilePreview(file); } hiddenFileInput.element().value = ""; + return this; } /** Uploads all added files to the server. */ - public void uploadAllFiles() { + public FileUpload uploadAllFiles() { addedFileItems.forEach(fileItem -> fileItem.upload(requestSender)); + return this; + } + + @Override + public UploadConfig getOwnConfig() { + return config; + } + + public FileUpload setConfig(UploadConfig config) { + this.config = config; + return this; } /** @@ -353,7 +392,7 @@ public void uploadAllFiles() { */ private void addFilePreview(File file) { if (isMultiUpload()) { - removeFileItems(); + removeUploadedFiles(); } FileItem fileItem = FileItem.create(file, new UploadOptions(), filePreviewFactory, this); @@ -397,6 +436,12 @@ public HTMLDivElement element() { */ public FileUpload setMultiUpload(boolean multiUpload) { hiddenFileInput.element().multiple = multiUpload; + if (multiUpload) { + hiddenFileInput.setAttribute("multiple", true); + } else { + hiddenFileInput.removeAttribute("multiple"); + } + return this; } @@ -511,6 +556,13 @@ public FileUpload removeFileItems() { return this; } + private void removeUploadedFiles() { + List uploaded = + addedFileItems.stream().filter(FileItem::isUploaded).collect(Collectors.toList()); + addedFileItems.removeAll(uploaded); + uploaded.forEach(FileItem::remove); + } + /** * Gets a list of file item handlers that are executed when a file is added to the component. * From aa16bd36dccc5b4654a9f41960fb8c3490473410 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 15:26:56 +0300 Subject: [PATCH 11/21] fix #843 DominoUIConfig for different parts of the application --- .../header/DelayedHeaderFilterInput.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/filter/header/DelayedHeaderFilterInput.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/filter/header/DelayedHeaderFilterInput.java index a84d746b2..73d202712 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/filter/header/DelayedHeaderFilterInput.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/filter/header/DelayedHeaderFilterInput.java @@ -22,6 +22,8 @@ import elemental2.dom.HTMLElement; import elemental2.dom.HTMLInputElement; +import org.dominokit.domino.ui.config.HasComponentConfig; +import org.dominokit.domino.ui.config.SearchConfig; import org.dominokit.domino.ui.datatable.ColumnConfig; import org.dominokit.domino.ui.datatable.model.Category; import org.dominokit.domino.ui.datatable.model.Filter; @@ -30,7 +32,6 @@ import org.dominokit.domino.ui.datatable.plugins.column.ColumnHeaderFilterPlugin; import org.dominokit.domino.ui.forms.InputFormField; import org.dominokit.domino.ui.utils.DelayedTextInput; -import org.dominokit.domino.ui.utils.DominoUIConfig; import org.dominokit.domino.ui.utils.HasPlaceHolder; /** @@ -44,9 +45,10 @@ */ public abstract class DelayedHeaderFilterInput< B extends InputFormField, T, V> - implements ColumnHeaderFilterPlugin.HeaderFilter { + implements ColumnHeaderFilterPlugin.HeaderFilter, HasComponentConfig { private B input; private DelayedTextInput delayedTextInput; + private SearchConfig config; /** Creates a new instance of DelayedHeaderFilterInput with a default placeholder. */ public DelayedHeaderFilterInput() { @@ -68,8 +70,16 @@ public DelayedHeaderFilterInput(String placeHolder) { delayedTextInput = DelayedTextInput.create( - getInputElement(), - DominoUIConfig.CONFIG.getUIConfig().getTableTextHeaderFilterSearchDelay()); + getInputElement(), getConfig().getTableTextHeaderFilterSearchDelay()); + } + + public void setOwnConfig(SearchConfig config) { + this.config = config; + } + + @Override + public SearchConfig getOwnConfig() { + return config; } /** From 57e42b0a7a2d83ab86fb0a9d3f36396069ea652a Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 15 Jul 2024 16:05:33 +0300 Subject: [PATCH 12/21] fix #944 NPE at AdvancedPaginationPlugin --- .../dominokit/domino/ui/pagination/AdvancedPagination.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/pagination/AdvancedPagination.java b/domino-ui/src/main/java/org/dominokit/domino/ui/pagination/AdvancedPagination.java index 581dfd411..cc657eb18 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/pagination/AdvancedPagination.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/pagination/AdvancedPagination.java @@ -15,6 +15,7 @@ */ package org.dominokit.domino.ui.pagination; +import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import static org.dominokit.domino.ui.utils.Domino.*; @@ -133,7 +134,9 @@ public AdvancedPagination(int pages, int pageSize) { pagesSelect = Select.create() .addChangeListener( - (oldValue, newValue) -> moveToPage(newValue, isChangeListenersPaused())); + (oldValue, newValue) -> { + moveToPage(isNull(newValue) ? 1 : newValue, isChangeListenersPaused()); + }); pagesList.insertAfter( PagerNavItem.create(pagesSelect) From 28250c8b6d9759de5be660721a89577b22138a37 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Thu, 25 Jul 2024 20:44:19 +0300 Subject: [PATCH 13/21] fix #948 Memory leak in menu and Popover. --- .../org/dominokit/domino/ui/menu/Menu.java | 49 +++++++++++++------ .../dominokit/domino/ui/popover/Popover.java | 17 +++---- .../domino/ui/utils/BaseDominoElement.java | 35 +++++++++++++ 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java b/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java index 1bb8ed0c7..c4ec45df1 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/menu/Menu.java @@ -156,6 +156,7 @@ public class Menu extends BaseDominoElement> private EventListener lostFocusListener; private boolean closeOnBlur = DominoUIConfig.CONFIG.isClosePopupOnBlur(); private OpenMenuCondition openMenuCondition = (menu) -> true; + private List mediaQueryRecords = new ArrayList<>(); /** * Factory method to create a new Menu instance. @@ -355,19 +356,6 @@ public Menu() { element.addEventListener("keydown", keyboardNavigation); - MediaQuery.addOnSmallAndDownListener( - () -> { - if (centerOnSmallScreens) { - this.smallScreen = true; - } - }); - MediaQuery.addOnMediumAndUpListener( - () -> { - if (centerOnSmallScreens) { - this.smallScreen = false; - backArrowContainer.remove(); - } - }); backIcon = LazyChild.of(Icons.keyboard_backspace().addCss(dui_menu_back_icon), menuHeader); backIcon.whenInitialized( () -> { @@ -403,6 +391,38 @@ public Menu() { } }; + nowAndWhenAttached( + () -> { + mediaQueryRecords.add( + MediaQuery.addOnSmallAndDownListener( + () -> { + if (centerOnSmallScreens) { + this.smallScreen = true; + } + })); + + mediaQueryRecords.add( + MediaQuery.addOnMediumAndUpListener( + () -> { + if (centerOnSmallScreens) { + this.smallScreen = false; + backArrowContainer.remove(); + } + })); + + DomGlobal.document.body.addEventListener("blur", lostFocusListener, true); + if (this.dropDown) { + document.addEventListener("scroll", repositionListener, true); + } + }); + + nowAndWhenDetached( + () -> { + DomGlobal.document.body.removeEventListener("blur", lostFocusListener, true); + document.removeEventListener("scroll", repositionListener, true); + mediaQueryRecords.forEach(MediaQuery.MediaQueryListenerRecord::remove); + }); + this.addEventListener(EventType.touchstart.getName(), Event::stopPropagation); this.addEventListener(EventType.touchend.getName(), Event::stopPropagation); } @@ -1378,7 +1398,6 @@ private void doOpen(boolean focus) { menuHeader.get().insertFirst(backArrowContainer); } show(); - DomGlobal.document.body.addEventListener("blur", lostFocusListener, true); } } @@ -1570,7 +1589,6 @@ public Menu close() { menuTarget -> { menuTarget.getTargetElement().element().focus(); }); - DomGlobal.document.body.removeEventListener("blur", lostFocusListener, true); if (isSearchable()) { searchBox.get().clearSearch(); } @@ -1785,7 +1803,6 @@ private void setDropDown(boolean dropdown) { if (dropdown) { this.setAttribute("domino-ui-root-menu", true).setAttribute(DOMINO_UI_AUTO_CLOSABLE, true); menuElement.elevate(Elevation.LEVEL_1); - document.addEventListener("scroll", repositionListener, true); } else { this.removeAttribute("domino-ui-root-menu").removeAttribute(DOMINO_UI_AUTO_CLOSABLE); menuElement.elevate(Elevation.NONE); diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/popover/Popover.java b/domino-ui/src/main/java/org/dominokit/domino/ui/popover/Popover.java index d4caa916e..b664fd086 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/popover/Popover.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/popover/Popover.java @@ -21,6 +21,8 @@ import elemental2.dom.EventListener; import elemental2.dom.HTMLElement; +import java.util.ArrayList; +import java.util.List; import org.dominokit.domino.ui.IsElement; import org.dominokit.domino.ui.animations.Transition; import org.dominokit.domino.ui.collapsible.AnimationCollapseStrategy; @@ -47,6 +49,7 @@ */ public class Popover extends BasePopover { + private static boolean asDialog = false; /** Static initialization block to add a global click event listener for closing popovers. */ static { document.body.addEventListener( @@ -54,14 +57,18 @@ public class Popover extends BasePopover { element -> { ModalBackDrop.INSTANCE.closePopovers(""); }); + + MediaQuery.addOnSmallAndDownListener(() -> asDialog = true); + + MediaQuery.addOnMediumAndUpListener(() -> asDialog = false); } private final EventListener showListener; private boolean openOnClick = true; private boolean closeOnEscape = true; - private boolean asDialog = false; private final DropDirection dialog = DropDirection.MIDDLE_SCREEN; private boolean modal = false; + private final List mediaListenersRecords = new ArrayList<>(); /** * Creates a new `Popover` instance for the specified HTML element target. @@ -102,14 +109,6 @@ public Popover(HTMLElement target) { new AnimationCollapseStrategy( Transition.FADE_IN, Transition.FADE_OUT, CollapsibleDuration._300ms)); - MediaQuery.addOnSmallAndDownListener( - () -> { - this.asDialog = true; - }); - MediaQuery.addOnMediumAndUpListener( - () -> { - this.asDialog = false; - }); addCollapseListener(() -> removeEventListener(DUI_REMOVE_POPOVERS, closeAllListener)); } 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 d3ead7fe6..fa22d7d7b 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 @@ -694,6 +694,24 @@ public T nowOrWhenAttached(Runnable handler) { return (T) this; } + /** + * Executes a given handler either immediately if the element is already detached from the DOM or + * when it gets detached. + * + * @param handler The handler to execute. + * @return The modified DOM element. + */ + @Editor.Ignore + public T nowOrWhenDetached(Runnable handler) { + if (isAttached()) { + onDetached(mutationRecord -> handler.run()); + } else { + handler.run(); + } + dominoUuidInitializer.apply(); + return (T) this; + } + /** * Executes a given handler when the element is attached to the DOM. If the element is already * attached, the handler is executed immediately. @@ -711,6 +729,23 @@ public T nowAndWhenAttached(Runnable handler) { return (T) this; } + /** + * Executes a given handler when the element is detached from the DOM. If the element is already + * detached, the handler is executed immediately. + * + * @param handler The handler to execute. + * @return The modified DOM element. + */ + @Editor.Ignore + public T nowAndWhenDetached(Runnable handler) { + if (!isAttached()) { + handler.run(); + } + onDetached(mutationRecord -> handler.run()); + dominoUuidInitializer.apply(); + return (T) this; + } + /** * Registers a resize handler to be notified when the size of this element changes. * From 896c9deb72a2f4bbd402d36b8b496ad5d8d8ad51 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Fri, 26 Jul 2024 17:23:26 +0300 Subject: [PATCH 14/21] fix #940 SuggestBox clearValue(...) does not clear value if it isnt predefined choice --- .../org/dominokit/domino/ui/forms/suggest/SuggestBox.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java index 626621ea2..f065c1511 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/forms/suggest/SuggestBox.java @@ -188,7 +188,6 @@ protected SuggestBox clearValue(boolean silent) { onOptionDeselected(selectedOption); getInputElement().element().value = null; }); - if (!silent) { triggerClearListeners(oldValue); triggerChangeListeners(oldValue, getValue()); @@ -197,6 +196,8 @@ protected SuggestBox clearValue(boolean silent) { if (isAutoValidation()) { autoValidate(); } + } else { + withPauseChangeListenersToggle(true, field -> getInputElement().element().value = null); } return this; @@ -212,7 +213,7 @@ public String getStringValue() { if (nonNull(this.selectedOption)) { return String.valueOf(this.selectedOption.getValue()); } - return null; + return getInputElement().element().value; } /** Handles actions to be performed after an option is selected. */ From 816bc36ec6c1f7e3427704108b6dbc0d5ba51c9d Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Fri, 26 Jul 2024 17:44:26 +0300 Subject: [PATCH 15/21] fix #947 Calling SetTitle twice on NavBar removes description --- .../dominokit/domino/ui/layout/NavBar.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/layout/NavBar.java b/domino-ui/src/main/java/org/dominokit/domino/ui/layout/NavBar.java index 0ff40e737..51abfd14c 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/layout/NavBar.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/layout/NavBar.java @@ -24,6 +24,7 @@ import org.dominokit.domino.ui.elements.HeadingElement; import org.dominokit.domino.ui.elements.NavElement; import org.dominokit.domino.ui.elements.SmallElement; +import org.dominokit.domino.ui.elements.SpanElement; import org.dominokit.domino.ui.utils.*; /** @@ -57,6 +58,7 @@ public class NavBar extends BaseDominoElement { private NavElement root; private HeadingElement title; + private SpanElement titleTextElement; private LazyChild description; private DivElement body; @@ -84,7 +86,7 @@ public NavBar() { root = nav() .addCss(dui_nav_bar) - .appendChild(title = h(4).addCss(dui_nav_title)) + .appendChild(title = h(4).appendChild(titleTextElement = span()).addCss(dui_nav_title)) .appendChild(body = div().addCss(dui_nav_body)); description = LazyChild.of(small().addCss(dui_nav_description), title); init(this); @@ -118,7 +120,7 @@ public NavBar(String title, String description) { * @return This {@code NavBar} instance. */ public NavBar setTitle(String title) { - this.title.setTextContent(title); + this.titleTextElement.setTextContent(title); return this; } @@ -159,6 +161,17 @@ public NavBar withDescription(ChildHandler handler) { return this; } + /** + * Allows customization of the title text element. + * + * @param handler The handler for customizing the title text element. + * @return This {@code NavBar} instance. + */ + public NavBar withTitleTextElement(ChildHandler handler) { + handler.apply(this, titleTextElement); + return this; + } + /** * Gets the title element. * @@ -186,6 +199,11 @@ public String getTitle() { return title.getTextContent(); } + /** @return the element containing the text of the title. */ + public SpanElement getTitleTextElement() { + return titleTextElement; + } + /** * Gets the text of the description displayed in the navigation bar. * From 45af1fc837d2c7ca871721cf6c21542d6088e618 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Fri, 26 Jul 2024 17:46:39 +0300 Subject: [PATCH 16/21] file upload enhancements Removing the file item will also remove the hosting column element. file handler now are called after the file is appended. cancel now works even if the request is not yet sent. --- .../upload/DefaultFilePreviewContainer.java | 7 +-- .../dominokit/domino/ui/upload/FileItem.java | 2 +- .../domino/ui/upload/FileUpload.java | 51 +++++++++++++++---- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java index c22e2568b..73ed1f8d2 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java @@ -17,7 +17,6 @@ import static org.dominokit.domino.ui.utils.Domino.*; -import elemental2.dom.DomGlobal; import elemental2.dom.HTMLDivElement; import org.dominokit.domino.ui.grid.Column; import org.dominokit.domino.ui.grid.Row; @@ -57,11 +56,7 @@ public DefaultFilePreviewContainer appendChild(FileItem fileItem) { .apply( self -> { self.appendChild(fileItem); - fileItem.onDetached( - mutationRecord -> { - DomGlobal.console.info("delete columns too ------------------"); - self.remove(); - }); + fileItem.onDetached(mutationRecord -> self.remove()); })); return this; } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileItem.java b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileItem.java index f6884df22..70196f88d 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileItem.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileItem.java @@ -442,8 +442,8 @@ public List getSuccessUploadHandlers() { * @return This FileItem instance for method chaining. */ public FileItem cancel() { + canceled = true; if (request != null) { - canceled = true; request.abort(); } return this; diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java index 3a11a6add..54d8802f0 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/FileUpload.java @@ -16,11 +16,23 @@ package org.dominokit.domino.ui.upload; import static java.util.Objects.nonNull; -import static org.dominokit.domino.ui.utils.Domino.*; +import static org.dominokit.domino.ui.utils.Domino.div; +import static org.dominokit.domino.ui.utils.Domino.elementOf; +import static org.dominokit.domino.ui.utils.Domino.input; import static org.dominokit.domino.ui.utils.DominoUIConfig.CONFIG; -import elemental2.dom.*; -import java.util.*; +import elemental2.dom.DragEvent; +import elemental2.dom.Element; +import elemental2.dom.File; +import elemental2.dom.FileList; +import elemental2.dom.HTMLDivElement; +import elemental2.dom.HTMLElement; +import elemental2.dom.XMLHttpRequest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Collectors; import jsinterop.base.Js; @@ -100,6 +112,7 @@ public class FileUpload extends BaseDominoElement private DropEffect dropEffect; private UploadConfig config; + private boolean showPreview = true; /** * Creates a new instance of the `FileUpload` component. @@ -396,17 +409,20 @@ private void addFilePreview(File file) { } FileItem fileItem = FileItem.create(file, new UploadOptions(), filePreviewFactory, this); + fileItem.addRemoveHandler( + removedFile -> { + addedFileItems.remove(fileItem); + }); + fileItemHandlers.forEach(handler -> handler.handle(fileItem)); fileItem.validateSize(); - filesContainer.appendChild(fileItem); - addedFileItems.add(fileItem); + if (showPreview) { + filesContainer.appendChild(fileItem); + } - fileItem.addRemoveHandler( - removedFile -> { - addedFileItems.remove(fileItem); - }); + addedFileItems.add(fileItem); if (fileItem.isCanceled()) { fileItem.remove(); @@ -627,6 +643,23 @@ public FileUpload setDropEffect(DropEffect dropEffect) { return this; } + /** @return true if uploaded files will show a preview in the preview container */ + public boolean isShowPreview() { + return showPreview; + } + + /** + * When set to true, uploaded files will show a preview in the preview container, otherwise they + * wont + * + * @param showPreview boolean. + * @return same component instance + */ + public FileUpload setShowPreview(boolean showPreview) { + this.showPreview = showPreview; + return this; + } + /** * A functional interface for handling file items when they are added to the `FileUpload` * component. From af028112369fd66c3053cb81d7ee6f647591708e Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Sun, 28 Jul 2024 15:24:20 +0300 Subject: [PATCH 17/21] fix #932 Wrong UI interaction between datatable SummaryPlugin and EmptyStatePlugin Adding the ability to remove the summary rows in case of empty data set --- .../plugins/summary/SummaryPlugin.java | 55 ++++++++++++++++++- .../plugins/summary/SummaryPluginConfig.java | 43 +++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java index 91e9928e8..af08cf30f 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java @@ -16,11 +16,16 @@ package org.dominokit.domino.ui.datatable.plugins.summary; +import static java.util.Objects.isNull; + import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.dominokit.domino.ui.datatable.DataTable; +import org.dominokit.domino.ui.datatable.events.TableDataUpdatedEvent; +import org.dominokit.domino.ui.datatable.events.TableEvent; import org.dominokit.domino.ui.datatable.plugins.DataTablePlugin; +import org.dominokit.domino.ui.datatable.plugins.HasPluginConfig; import org.dominokit.domino.ui.elements.TFootElement; import org.dominokit.domino.ui.utils.BaseDominoElement; @@ -40,11 +45,13 @@ * @param The type of data in the DataTable. * @param The type of data in the summary row. */ -public class SummaryPlugin implements DataTablePlugin { +public class SummaryPlugin + implements DataTablePlugin, HasPluginConfig, SummaryPluginConfig> { private List> summaryRows = new ArrayList<>(); private DataTable dataTable; private TFootElement footer; + private SummaryPluginConfig config = new SummaryPluginConfig(); /** * Initializes the SummaryPlugin with the DataTable. @@ -74,8 +81,10 @@ public void onFooterAdded(DataTable datatable) { * @return This SummaryPlugin instance. */ public SummaryPlugin setSummaryRecords(Collection records) { - summaryRows.forEach(BaseDominoElement::remove); - summaryRows.clear(); + removeSummaryRecords(); + if (this.config.isRemoveOnEmptyData() && this.dataTable.getRecords().isEmpty()) { + return this; + } List recordsList = new ArrayList<>(records); for (int i = 0; i < recordsList.size(); i++) { SummaryRow summaryRow = new SummaryRow<>(recordsList.get(i), i, this.dataTable); @@ -86,6 +95,46 @@ public SummaryPlugin setSummaryRecords(Collection records) { return this; } + public void removeSummaryRecords() { + summaryRows.forEach(BaseDominoElement::remove); + summaryRows.clear(); + } + + @Override + public void handleEvent(TableEvent event) { + if (TableDataUpdatedEvent.DATA_UPDATED.equals(event.getType())) { + if (config.isRemoveOnEmptyData() && ((TableDataUpdatedEvent) event).getData().isEmpty()) { + removeSummaryRecords(); + } + } + } + + /** + * Sets the configuration for the SummaryPlugin. + * + * @param config The SummaryPlugin to set. + * @return The SummaryPlugin instance. + */ + @Override + public SummaryPlugin setConfig(SummaryPluginConfig config) { + if (isNull(config)) { + this.config = new SummaryPluginConfig(); + } else { + this.config = config; + } + return this; + } + + /** + * Gets the current configuration of the SummaryPlugin. + * + * @return The current SummaryPluginConfig. + */ + @Override + public SummaryPluginConfig getConfig() { + return config; + } + /** * Specifies the order in which this plugin should be applied relative to other plugins. Plugins * with lower order values are applied first. diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java new file mode 100644 index 000000000..cf848d7ba --- /dev/null +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java @@ -0,0 +1,43 @@ +/* + * 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.datatable.plugins.summary; + +import org.dominokit.domino.ui.datatable.plugins.PluginConfig; + +public class SummaryPluginConfig implements PluginConfig { + + private boolean removeOnEmptyData = false; + + /** + * @return boolean, true will cause the plugin to remove the summary records for empty data + * tables, false will keep them, default to false + */ + public boolean isRemoveOnEmptyData() { + return removeOnEmptyData; + } + + /** + * Use this to configure the plugin to remove/keep the summary records when the datatable has no + * records. + * + * @param removeOnEmptyData boolean, true to remove the records, false to keep them. + * @return same config instance. + */ + public SummaryPluginConfig setRemoveOnEmptyData(boolean removeOnEmptyData) { + this.removeOnEmptyData = removeOnEmptyData; + return this; + } +} From 074de3dd19b6e8b221caff9234108b837994f0fb Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Sun, 28 Jul 2024 19:37:04 +0300 Subject: [PATCH 18/21] fix #932 Wrong UI interaction between datatable SummaryPlugin and EmptyStatePlugin Improve the construction of summary plugin config and add a global default configuration. --- .../domino/ui/config/DatatableConfig.java | 22 +++++++++++++++++++ .../dominokit/domino/ui/config/UIConfig.java | 3 ++- .../plugins/summary/SummaryPlugin.java | 4 ++-- .../plugins/summary/SummaryPluginConfig.java | 18 +++++++++++++-- 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/config/DatatableConfig.java diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/DatatableConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/DatatableConfig.java new file mode 100644 index 000000000..16a27ac28 --- /dev/null +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/DatatableConfig.java @@ -0,0 +1,22 @@ +/* + * 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 DatatableConfig extends ComponentConfig { + default boolean isRemoveSummaryRecordsForEmptyTable() { + return false; + } +} 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 a39c60517..39c563a94 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 @@ -30,4 +30,5 @@ public interface UIConfig StepperConfig, CalendarConfig, TimePickerConfig, - DelayedActionConfig {} + DelayedActionConfig, + DatatableConfig {} diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java index af08cf30f..4974805b7 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPlugin.java @@ -51,7 +51,7 @@ public class SummaryPlugin private List> summaryRows = new ArrayList<>(); private DataTable dataTable; private TFootElement footer; - private SummaryPluginConfig config = new SummaryPluginConfig(); + private SummaryPluginConfig config = SummaryPluginConfig.of(); /** * Initializes the SummaryPlugin with the DataTable. @@ -118,7 +118,7 @@ public void handleEvent(TableEvent event) { @Override public SummaryPlugin setConfig(SummaryPluginConfig config) { if (isNull(config)) { - this.config = new SummaryPluginConfig(); + this.config = SummaryPluginConfig.of(); } else { this.config = config; } diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java index cf848d7ba..f19c772ba 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java @@ -15,15 +15,29 @@ */ package org.dominokit.domino.ui.datatable.plugins.summary; +import org.dominokit.domino.ui.config.DatatableConfig; import org.dominokit.domino.ui.datatable.plugins.PluginConfig; +import org.dominokit.domino.ui.utils.DominoUIConfig; public class SummaryPluginConfig implements PluginConfig { - private boolean removeOnEmptyData = false; + private boolean removeOnEmptyData; + + public SummaryPluginConfig(boolean removeOnEmptyData) { + this.removeOnEmptyData = removeOnEmptyData; + } + + public static SummaryPluginConfig of(){ + return new SummaryPluginConfig(DominoUIConfig.CONFIG.getUIConfig().isRemoveSummaryRecordsForEmptyTable()); + } + + public static SummaryPluginConfig of(boolean removeOnEmptyData){ + return new SummaryPluginConfig(removeOnEmptyData); + } /** * @return boolean, true will cause the plugin to remove the summary records for empty data - * tables, false will keep them, default to false + * tables, false will keep them, default to {@link DatatableConfig#isRemoveSummaryRecordsForEmptyTable()} */ public boolean isRemoveOnEmptyData() { return removeOnEmptyData; From 5bf17457596b478cebb1301bd69f14ed33764e65 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Sun, 28 Jul 2024 19:40:40 +0300 Subject: [PATCH 19/21] fix #946 Enhance datepicker: API to single days for deactivating etc. --- .../plugins/summary/SummaryPluginConfig.java | 10 +++--- .../domino/ui/datepicker/Calendar.java | 32 +++++++++---------- .../domino/ui/datepicker/CalendarDay.java | 15 ++++----- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java index f19c772ba..5247b3ff0 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java @@ -27,17 +27,19 @@ public SummaryPluginConfig(boolean removeOnEmptyData) { this.removeOnEmptyData = removeOnEmptyData; } - public static SummaryPluginConfig of(){ - return new SummaryPluginConfig(DominoUIConfig.CONFIG.getUIConfig().isRemoveSummaryRecordsForEmptyTable()); + public static SummaryPluginConfig of() { + return new SummaryPluginConfig( + DominoUIConfig.CONFIG.getUIConfig().isRemoveSummaryRecordsForEmptyTable()); } - public static SummaryPluginConfig of(boolean removeOnEmptyData){ + public static SummaryPluginConfig of(boolean removeOnEmptyData) { return new SummaryPluginConfig(removeOnEmptyData); } /** * @return boolean, true will cause the plugin to remove the summary records for empty data - * tables, false will keep them, default to {@link DatatableConfig#isRemoveSummaryRecordsForEmptyTable()} + * tables, false will keep them, default to {@link + * DatatableConfig#isRemoveSummaryRecordsForEmptyTable()} */ public boolean isRemoveOnEmptyData() { return removeOnEmptyData; 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 4160f814b..78423aa6d 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 @@ -113,20 +113,21 @@ public Calendar(Date date, DateTimeFormatInfo dateTimeFormatInfo, CalendarInitCo this.dateTimeFormatInfo = dateTimeFormatInfo; this.config = config; - this.root = - div() - .addCss(dui_calendar) - .apply(calendar -> header = LazyChild.of(CalendarHeader.create(this), calendar)) - .appendChild(selectors = CalendarSelectors.create(this)) - .appendChild( - calendarBody = - div() - .addCss(dui_calendar_body) - .appendChild(calendarMonth = CalendarMonth.create(this)) - .appendChild(yearMonthPicker = YearMonthPicker.create(this).hide())) - .apply( - calendar -> - this.footer = LazyChild.of(div().addCss(dui_calendar_footer), calendar)); + this.root = div().addCss(dui_calendar); + + getConfig().getPlugins().forEach(plugin -> plugin.onInit(this)); + init(this); + + this.root + .apply(calendar -> header = LazyChild.of(CalendarHeader.create(this), calendar)) + .appendChild(selectors = CalendarSelectors.create(this)) + .appendChild( + calendarBody = + div() + .addCss(dui_calendar_body) + .appendChild(calendarMonth = CalendarMonth.create(this)) + .appendChild(yearMonthPicker = YearMonthPicker.create(this).hide())) + .apply(calendar -> this.footer = LazyChild.of(div().addCss(dui_calendar_footer), calendar)); this.root.addEventListener( CalendarCustomEvents.DATE_NAVIGATION_CHANGED, @@ -168,11 +169,10 @@ public Calendar(Date date, DateTimeFormatInfo dateTimeFormatInfo, CalendarInitCo calendarBody.removeCss(dui_p_x_1_5); } }); - init(this); + onDateViewUpdate(this.date); onDateSelectionChanged(this.date); onDateTimeFormatChanged(); - getConfig().getPlugins().forEach(plugin -> plugin.onInit(this)); } /** diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/CalendarDay.java b/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/CalendarDay.java index 873552117..3798310ba 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/CalendarDay.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datepicker/CalendarDay.java @@ -15,7 +15,6 @@ */ package org.dominokit.domino.ui.datepicker; -import static org.dominokit.domino.ui.utils.Domino.*; import static org.dominokit.domino.ui.utils.Domino.div; import static org.dominokit.domino.ui.utils.Domino.span; @@ -65,13 +64,6 @@ public CalendarDay(IsCalendar calendar, Date date, int day, boolean inRange) { root = div() - .addClickListener( - evt -> { - this.dispatchEvent( - CalendarCustomEvents.dateSelectionChanged( - new Date(this.date.getYear(), this.date.getMonth(), this.date.getDate()) - .getTime())); - }) .addCss( dui_calendar_day, BooleanCssClass.of(dui_month_day_in_range, inRange), @@ -84,6 +76,13 @@ public CalendarDay(IsCalendar calendar, Date date, int day, boolean inRange) { .addCss(dui_calendar_day_number) .textContent(String.valueOf(date.getDate()))); init(this); + addClickListener( + evt -> { + this.dispatchEvent( + CalendarCustomEvents.dateSelectionChanged( + new Date(this.date.getYear(), this.date.getMonth(), this.date.getDate()) + .getTime())); + }); } /** From 1a7800a09c46fde4de7479a372f57378ff09d5f2 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Sun, 28 Jul 2024 22:49:06 +0300 Subject: [PATCH 20/21] fix #902 add scrollwheel support to carousel --- .../domino/ui/carousel/Carousel.java | 41 +++++++++++++++---- .../domino/ui/config/CarouselConfig.java | 23 +++++++++++ .../dominokit/domino/ui/config/UIConfig.java | 3 +- 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 domino-ui/src/main/java/org/dominokit/domino/ui/config/CarouselConfig.java diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/carousel/Carousel.java b/domino-ui/src/main/java/org/dominokit/domino/ui/carousel/Carousel.java index 470b24dc1..33e45b849 100644 --- a/domino-ui/src/main/java/org/dominokit/domino/ui/carousel/Carousel.java +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/carousel/Carousel.java @@ -19,11 +19,16 @@ import static org.dominokit.domino.ui.utils.Domino.*; import elemental2.dom.HTMLDivElement; +import elemental2.dom.WheelEvent; import java.util.ArrayList; import java.util.List; +import jsinterop.base.Js; +import org.dominokit.domino.ui.config.CarouselConfig; +import org.dominokit.domino.ui.config.HasComponentConfig; import org.dominokit.domino.ui.elements.AnchorElement; import org.dominokit.domino.ui.elements.DivElement; import org.dominokit.domino.ui.elements.OListElement; +import org.dominokit.domino.ui.events.EventType; import org.dominokit.domino.ui.icons.lib.Icons; import org.dominokit.domino.ui.style.CssClass; import org.dominokit.domino.ui.style.GenericCss; @@ -39,7 +44,8 @@ * * @see BaseDominoElement */ -public class Carousel extends BaseDominoElement { +public class Carousel extends BaseDominoElement + implements HasComponentConfig { private final OListElement indicatorsElement; private final DivElement slidesElement; @@ -57,6 +63,7 @@ public class Carousel extends BaseDominoElement { private Slide targetSlide; private int autoSlideDuration = 3000; private boolean attached = false; + private CarouselConfig carouselConfig; /** * Factory method to create an empty Carousel @@ -69,7 +76,6 @@ public static Carousel create() { /** Creates and empty Carousel */ public Carousel() { - element = div() .appendChild(indicatorsElement = ol().addCss(carousel_indicators)) @@ -89,11 +95,7 @@ public Carousel() { .appendChild( Icons.chevron_right() .addCss(GenericCss.dui_vertical_center, dui_font_size_12)) - .addEventListener( - "click", - evt -> { - next(); - })) + .addEventListener("click", evt -> next())) .addCss(carousel); timer = new Timer() { @@ -105,6 +107,21 @@ public void run() { addAttachListener(); addDetachListener(); init(this); + addEventListener( + EventType.wheel.getName(), + evt -> { + if (getConfig().isScrollCarouselWithWheel()) { + evt.preventDefault(); + WheelEvent wheelEvent = Js.uncheckedCast(evt); + if (wheelEvent.deltaY > 0) { + nextSlide(); + } + + if (wheelEvent.deltaY < 0) { + prevSlide(); + } + } + }); } /** @@ -406,6 +423,16 @@ public Slide getActiveSlide() { return activeSlide; } + @Override + public CarouselConfig getOwnConfig() { + return carouselConfig; + } + + public Carousel setConfig(CarouselConfig config) { + this.carouselConfig = config; + return this; + } + public enum SlideDirection { NONE, /** CSS class for previous indicator */ diff --git a/domino-ui/src/main/java/org/dominokit/domino/ui/config/CarouselConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/CarouselConfig.java new file mode 100644 index 000000000..120ec447c --- /dev/null +++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/CarouselConfig.java @@ -0,0 +1,23 @@ +/* + * 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 CarouselConfig extends ComponentConfig { + /** @return boolean, true to allow scrolling a carousel with mouse scroll wheel. */ + default boolean isScrollCarouselWithWheel() { + return false; + } +} 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 39c563a94..9d3c58307 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 @@ -31,4 +31,5 @@ public interface UIConfig CalendarConfig, TimePickerConfig, DelayedActionConfig, - DatatableConfig {} + DatatableConfig, + CarouselConfig {} From 723e9a00160e859aa8b3fbfe7858591938e4f060 Mon Sep 17 00:00:00 2001 From: "Ahmad K. Bawaneh" Date: Mon, 29 Jul 2024 19:57:23 +0300 Subject: [PATCH 21/21] Update versions for release --- domino-ui-shared/pom.xml | 2 +- domino-ui-tools/mdi-icons-processor/pom.xml | 2 +- domino-ui-tools/pom.xml | 2 +- domino-ui-webjar/pom.xml | 2 +- domino-ui/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/domino-ui-shared/pom.xml b/domino-ui-shared/pom.xml index 1f341d698..67232f605 100644 --- a/domino-ui-shared/pom.xml +++ b/domino-ui-shared/pom.xml @@ -5,7 +5,7 @@ domino-ui-parent org.dominokit - HEAD-SNAPSHOT + 2.0.2 jar 4.0.0 diff --git a/domino-ui-tools/mdi-icons-processor/pom.xml b/domino-ui-tools/mdi-icons-processor/pom.xml index 178f2d8e9..e51f5755c 100644 --- a/domino-ui-tools/mdi-icons-processor/pom.xml +++ b/domino-ui-tools/mdi-icons-processor/pom.xml @@ -5,7 +5,7 @@ domino-ui-tools org.dominokit - HEAD-SNAPSHOT + 2.0.2 4.0.0 diff --git a/domino-ui-tools/pom.xml b/domino-ui-tools/pom.xml index 83024dce5..0cf2c6f84 100644 --- a/domino-ui-tools/pom.xml +++ b/domino-ui-tools/pom.xml @@ -5,7 +5,7 @@ domino-ui-parent org.dominokit - HEAD-SNAPSHOT + 2.0.2 4.0.0 diff --git a/domino-ui-webjar/pom.xml b/domino-ui-webjar/pom.xml index 6485a5624..1b3de4790 100644 --- a/domino-ui-webjar/pom.xml +++ b/domino-ui-webjar/pom.xml @@ -5,7 +5,7 @@ domino-ui-parent org.dominokit - HEAD-SNAPSHOT + 2.0.2 jar 4.0.0 diff --git a/domino-ui/pom.xml b/domino-ui/pom.xml index ef01cc082..b7941785e 100644 --- a/domino-ui/pom.xml +++ b/domino-ui/pom.xml @@ -6,7 +6,7 @@ org.dominokit domino-ui-parent - HEAD-SNAPSHOT + 2.0.2 domino-ui diff --git a/pom.xml b/pom.xml index 9c2d61604..e1bc3b3d7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.dominokit domino-ui-parent - HEAD-SNAPSHOT + 2.0.2 pom domino-ui-parent