diff --git a/domino-ui-shared/pom.xml b/domino-ui-shared/pom.xml
index 8dabbb838..67232f605 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
+ 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 e2e7801ef..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
- 2.0.1
+ 2.0.2
4.0.0
diff --git a/domino-ui-tools/pom.xml b/domino-ui-tools/pom.xml
index 1d008ed76..0cf2c6f84 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
+ 2.0.2
4.0.0
diff --git a/domino-ui-webjar/pom.xml b/domino-ui-webjar/pom.xml
index 2e5972d55..1b3de4790 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
+ 2.0.2
jar
4.0.0
diff --git a/domino-ui/pom.xml b/domino-ui/pom.xml
index d9b77dbee..b7941785e 100644
--- a/domino-ui/pom.xml
+++ b/domino-ui/pom.xml
@@ -6,7 +6,7 @@
org.dominokit
domino-ui-parent
- 2.0.1
+ 2.0.2
domino-ui
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/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/DelayedActionConfig.java b/domino-ui/src/main/java/org/dominokit/domino/ui/config/DelayedActionConfig.java
new file mode 100644
index 000000000..4653b86b7
--- /dev/null
+++ b/domino-ui/src/main/java/org/dominokit/domino/ui/config/DelayedActionConfig.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+ }
+
+ /**
+ * 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/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/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..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
@@ -29,4 +29,7 @@ public interface UIConfig
UploadConfig,
StepperConfig,
CalendarConfig,
- TimePickerConfig {}
+ TimePickerConfig,
+ DelayedActionConfig,
+ DatatableConfig,
+ CarouselConfig {}
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/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/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);
}
/**
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;
}
/**
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);
}
/**
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..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
@@ -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 = SummaryPluginConfig.of();
/**
* 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 = SummaryPluginConfig.of();
+ } 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..5247b3ff0
--- /dev/null
+++ b/domino-ui/src/main/java/org/dominokit/domino/ui/datatable/plugins/summary/SummaryPluginConfig.java
@@ -0,0 +1,59 @@
+/*
+ * 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.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;
+
+ 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 {@link
+ * DatatableConfig#isRemoveSummaryRecordsForEmptyTable()}
+ */
+ 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;
+ }
+}
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..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,
@@ -134,11 +135,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 +148,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);
@@ -170,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));
}
/**
@@ -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/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()));
+ });
}
/**
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/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/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/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..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
@@ -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.
@@ -265,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));
+ }
+ });
});
});
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..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
@@ -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.
@@ -175,7 +176,7 @@ public AbstractSuggestBox(SuggestionsStore store) {
})));
getInputElement()
- .onKeyDown(
+ .onKeyUp(
keyEvents -> {
keyEvents
.onArrowDown(
@@ -223,6 +224,14 @@ public AbstractSuggestBox(SuggestionsStore store) {
onBackspace();
}
}
+ })
+ .onDelete(
+ evt -> {
+ if (!isReadOnly() && !isDisabled()) {
+ evt.stopPropagation();
+ evt.preventDefault();
+ onBackspace();
+ }
});
});
}
@@ -263,12 +272,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();
}
/**
@@ -286,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();
@@ -703,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.
*
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/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/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;
}
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..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
@@ -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,8 +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);
triggerChangeListeners(oldValue, getValue());
@@ -194,6 +196,8 @@ protected SuggestBox clearValue(boolean silent) {
if (isAutoValidation()) {
autoValidate();
}
+ } else {
+ withPauseChangeListenersToggle(true, field -> getInputElement().element().value = null);
}
return this;
@@ -209,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. */
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/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/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/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.
*
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/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/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)
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/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/upload/DefaultFilePreviewContainer.java b/domino-ui/src/main/java/org/dominokit/domino/ui/upload/DefaultFilePreviewContainer.java
index faf549d54..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
@@ -18,6 +18,7 @@
import static org.dominokit.domino.ui.utils.Domino.*;
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 +51,13 @@ public DefaultFilePreviewContainer() {
*/
@Override
public DefaultFilePreviewContainer appendChild(FileItem fileItem) {
- rootRow.span2(fileItem);
+ rootRow.appendChild(
+ Column.span2()
+ .apply(
+ self -> {
+ self.appendChild(fileItem);
+ 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 3522538df..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,12 +16,25 @@
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;
import org.dominokit.domino.ui.IsElement;
import org.dominokit.domino.ui.config.HasComponentConfig;
@@ -98,6 +111,8 @@ public class FileUpload extends BaseDominoElement
private UploadRequestSender requestSender = (XMLHttpRequest::send);
private DropEffect dropEffect;
+ private UploadConfig config;
+ private boolean showPreview = true;
/**
* Creates a new instance of the `FileUpload` component.
@@ -195,7 +210,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 +225,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 +250,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 +333,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 +373,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,21 +405,24 @@ public void uploadAllFiles() {
*/
private void addFilePreview(File file) {
if (isMultiUpload()) {
- removeFileItems();
+ removeUploadedFiles();
}
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();
@@ -397,6 +452,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 +572,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.
*
@@ -575,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.
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.
*
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);
+ }
}
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.
diff --git a/pom.xml b/pom.xml
index a0bd89b7f..e1bc3b3d7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.dominokit
domino-ui-parent
- 2.0.1
+ 2.0.2
pom
domino-ui-parent
@@ -68,7 +68,7 @@
HEAD-SNAPSHOT
- 2.0.1
+ 2.0.2
11
11