From daa359b2e2772fdfa39e8aa368883983ec9aeacf Mon Sep 17 00:00:00 2001 From: ugur-vaadin Date: Mon, 23 Sep 2024 18:55:39 +0300 Subject: [PATCH] refactor: align event apis with web component --- .../flow/component/dashboard/Dashboard.java | 193 ++++++++++++++---- .../dashboard/DashboardItemMovedEvent.java | 101 +++------ .../dashboard/DashboardItemRemovedEvent.java | 46 ++--- .../dashboard/DashboardItemResizedEvent.java | 58 ++---- .../tests/DashboardDragReorderTest.java | 136 +++++++++++- .../tests/DashboardDragResizeTest.java | 72 ++++++- .../dashboard/tests/DashboardTest.java | 92 ++++++++- 7 files changed, 507 insertions(+), 191 deletions(-) diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java index 79646d1a5ea..454e16e3319 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/Dashboard.java @@ -11,8 +11,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -24,9 +26,14 @@ import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.dependency.NpmPackage; +import com.vaadin.flow.dom.DomEvent; +import com.vaadin.flow.dom.DomListenerRegistration; import com.vaadin.flow.dom.Element; import com.vaadin.flow.shared.Registration; +import elemental.json.JsonArray; +import elemental.json.JsonObject; + /** * @author Vaadin Ltd */ @@ -49,9 +56,9 @@ public class Dashboard extends Component implements HasWidgets { */ public Dashboard() { childDetachHandler = getChildDetachHandler(); - addItemMovedListener(this::onItemMoved); - addItemResizedListener(this::onItemResized); - addItemRemovedListener(this::onItemRemoved); + initItemMovedClientEventListener(); + initItemResizedClientEventListener(); + initItemRemovedClientEventListener(); } /** @@ -448,44 +455,113 @@ void removeChild(Component child) { }; } - private void onItemMoved(DashboardItemMovedEvent dashboardItemMovedEvent) { - if (!isEditable()) { - return; - } - reorderItems(dashboardItemMovedEvent.getReorderedItemsParent(), - dashboardItemMovedEvent.getReorderedItems()); - updateClient(); - } - - private void onItemResized( - DashboardItemResizedEvent dashboardItemResizedEvent) { - if (!isEditable()) { - return; - } - DashboardWidget resizedWidget = dashboardItemResizedEvent - .getResizedWidget(); - resizedWidget.setRowspan(dashboardItemResizedEvent.getRowspan()); - resizedWidget.setColspan(dashboardItemResizedEvent.getColspan()); - } - - private void onItemRemoved( - DashboardItemRemovedEvent dashboardItemRemovedEvent) { - if (!isEditable()) { - return; - } - dashboardItemRemovedEvent.getRemovedItem().removeFromParent(); - } - - private void reorderItems(Component reorderedItemParent, - List items) { - if (reorderedItemParent instanceof DashboardSection parentSection) { - parentSection.removeAll(); - items.stream().map(DashboardWidget.class::cast) - .forEach(parentSection::add); - } else { + private void initItemMovedClientEventListener() { + String itemKey = "event.detail.item"; + String itemsKey = "event.detail.items"; + String sectionKey = "event.detail.section"; + getElement().addEventListener("dashboard-item-moved-flow", e -> { + if (!isEditable()) { + return; + } + handleItemMovedClientEvent(e, itemKey, itemsKey, sectionKey); + updateClient(); + }).addEventData(itemKey).addEventData(itemsKey) + .addEventData(sectionKey); + } + + private void handleItemMovedClientEvent(DomEvent e, String itemKey, + String itemsKey, String sectionKey) { + int itemNodeId = (int) e.getEventData().getNumber(itemKey); + JsonArray itemsNodeIds = e.getEventData().getArray(itemsKey); + Integer sectionNodeId = e.getEventData().hasKey(sectionKey) + ? (int) e.getEventData().getNumber(sectionKey) + : null; + DashboardSection section = null; + List reorderedItems; + if (sectionNodeId == null) { + reorderedItems = getReorderedItemsList(itemsNodeIds, this); childrenComponents.clear(); - childrenComponents.addAll(items); + childrenComponents.addAll(reorderedItems); + } else { + section = getChildren() + .filter(child -> sectionNodeId + .equals(child.getElement().getNode().getId())) + .map(DashboardSection.class::cast).findAny().orElseThrow(); + reorderedItems = getReorderedItemsList( + getSectionItems(itemsNodeIds, sectionNodeId), section); + section.removeAll(); + reorderedItems.stream().map(DashboardWidget.class::cast) + .forEach(section::add); } + Component movedItem = reorderedItems.stream().filter( + item -> itemNodeId == item.getElement().getNode().getId()) + .findAny().orElseThrow(); + fireEvent(new DashboardItemMovedEvent(this, true, movedItem, + getChildren().toList(), section)); + } + + private void initItemResizedClientEventListener() { + String nodeIdKey = "event.detail.item.nodeid"; + String colspanKey = "event.detail.item.colspan"; + String rowspanKey = "event.detail.item.rowspan"; + getElement().addEventListener("dashboard-item-resized", e -> { + if (!isEditable()) { + return; + } + handleItemResizedClientEvent(e, nodeIdKey, colspanKey, rowspanKey); + updateClient(); + }).addEventData(nodeIdKey).addEventData(colspanKey) + .addEventData(rowspanKey); + } + + private void handleItemResizedClientEvent(DomEvent e, String nodeIdKey, + String colspanKey, String rowspanKey) { + int nodeId = (int) e.getEventData().getNumber(nodeIdKey); + int colspan = (int) e.getEventData().getNumber(colspanKey); + int rowspan = (int) e.getEventData().getNumber(rowspanKey); + DashboardWidget resizedWidget = getWidgets().stream() + .filter(child -> nodeId == child.getElement().getNode().getId()) + .findAny().orElseThrow(); + resizedWidget.setRowspan(rowspan); + resizedWidget.setColspan(colspan); + fireEvent(new DashboardItemResizedEvent(this, true, resizedWidget, + getChildren().toList())); + } + + private void initItemRemovedClientEventListener() { + String nodeIdKey = "event.detail.item.nodeid"; + DomListenerRegistration registration = getElement() + .addEventListener("dashboard-item-removed", e -> { + if (!isEditable()) { + return; + } + handleItemRemovedClientEvent(e, nodeIdKey); + updateClient(); + }); + registration.addEventData(nodeIdKey); + } + + private void handleItemRemovedClientEvent(DomEvent e, String nodeIdKey) { + int nodeId = (int) e.getEventData().getNumber(nodeIdKey); + Component removedItem = getRemovedItem(nodeId); + removedItem.removeFromParent(); + fireEvent(new DashboardItemRemovedEvent(this, true, removedItem, + getChildren().toList())); + } + + private Component getRemovedItem(int nodeId) { + return getChildren().map(item -> { + if (nodeId == item.getElement().getNode().getId()) { + return item; + } + if (item instanceof DashboardSection section) { + return section.getWidgets().stream() + .filter(sectionItem -> nodeId == sectionItem + .getElement().getNode().getId()) + .findAny().orElse(null); + } + return null; + }).filter(Objects::nonNull).findAny().orElseThrow(); } private void customizeItemMovedEvent() { @@ -499,9 +575,46 @@ function mapItems(items) { })); } const flowItemMovedEvent = new CustomEvent('dashboard-item-moved-flow', { - detail: { items: mapItems(e.detail.items), section: e.detail.section?.nodeid } + detail: { + item: e.detail.item.nodeid, + items: mapItems(e.detail.items), + section: e.detail.section?.nodeid + } }); this.dispatchEvent(flowItemMovedEvent); });"""); } + + private static List getReorderedItemsList( + JsonArray reorderedItemsFromClient, + Component reorderedItemsParent) { + Objects.requireNonNull(reorderedItemsFromClient); + Map nodeIdToItems = reorderedItemsParent + .getChildren() + .collect(Collectors.toMap( + item -> item.getElement().getNode().getId(), + Function.identity())); + List items = new ArrayList<>(); + for (int index = 0; index < reorderedItemsFromClient + .length(); index++) { + int nodeIdFromClient = (int) ((JsonObject) reorderedItemsFromClient + .get(index)).getNumber("nodeid"); + items.add(nodeIdToItems.get(nodeIdFromClient)); + } + return items; + } + + private static JsonArray getSectionItems(JsonArray items, + int sectionNodeId) { + for (int rootLevelIdx = 0; rootLevelIdx < items + .length(); rootLevelIdx++) { + JsonObject item = items.get(rootLevelIdx); + int itemNodeId = (int) item.getNumber("nodeid"); + if (sectionNodeId == itemNodeId) { + JsonObject sectionObj = items.get(rootLevelIdx); + return sectionObj.getArray("items"); + } + } + return null; + } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemMovedEvent.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemMovedEvent.java index dfef40aea87..4bc081bffea 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemMovedEvent.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemMovedEvent.java @@ -8,21 +8,12 @@ */ package com.vaadin.flow.component.dashboard; -import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.Optional; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEvent; import com.vaadin.flow.component.ComponentEventListener; -import com.vaadin.flow.component.DomEvent; -import com.vaadin.flow.component.EventData; - -import elemental.json.JsonArray; -import elemental.json.JsonObject; /** * Widget or section moved event of {@link Dashboard}. @@ -30,12 +21,13 @@ * @author Vaadin Ltd. * @see Dashboard#addItemMovedListener(ComponentEventListener) */ -@DomEvent("dashboard-item-moved-flow") public class DashboardItemMovedEvent extends ComponentEvent { - private final List reorderedItems; + private final Component item; + + private final List items; - private final Component reorderedItemsParent; + private final DashboardSection section; /** * Creates a dashboard item moved event. @@ -43,77 +35,50 @@ public class DashboardItemMovedEvent extends ComponentEvent { * @param source * Dashboard that contains the item that was moved * @param fromClient - * true if the event originated from the client - * side, false otherwise + * {@code true} if the event originated from the client side, + * {@code false} otherwise + * @param item + * The moved item * @param items - * The ordered items represented by node IDs as a - * {@link JsonArray} + * The root level items of the dashboard + * @param section + * The section that contains the moved item, {@code null} if the + * item is a direct child of the dashboard */ public DashboardItemMovedEvent(Dashboard source, boolean fromClient, - @EventData("event.detail.items") JsonArray items, - @EventData("event.detail.section") Integer sectionNodeId) { + Component item, List items, DashboardSection section) { super(source, fromClient); - if (sectionNodeId == null) { - reorderedItemsParent = source; - reorderedItems = getReorderedItemsList(items); - } else { - reorderedItemsParent = source.getChildren() - .filter(child -> sectionNodeId - .equals(child.getElement().getNode().getId())) - .map(DashboardSection.class::cast).findAny().orElseThrow(); - reorderedItems = getReorderedItemsList( - getSectionItems(items, sectionNodeId)); - } + this.item = item; + this.items = items; + this.section = section; } /** - * Returns the parent of the reordered items. Either a dashboard or a - * section. + * Returns the moved item * - * @return the parent of the reordered items + * @return the moved item */ - public Component getReorderedItemsParent() { - return reorderedItemsParent; + public Component getItem() { + return item; } /** - * Returns the list of the reordered item and its sibling items + * Returns the root level items of the dashboard * - * @return the list of the reordered item and its sibling items + * @return the root level items of the dashboard */ - public List getReorderedItems() { - return reorderedItems; - } - - private List getReorderedItemsList( - JsonArray reorderedItemsFromClient) { - Objects.requireNonNull(reorderedItemsFromClient); - Map nodeIdToItems = reorderedItemsParent - .getChildren() - .collect(Collectors.toMap( - item -> item.getElement().getNode().getId(), - Function.identity())); - List items = new ArrayList<>(); - for (int index = 0; index < reorderedItemsFromClient - .length(); index++) { - int nodeIdFromClient = (int) ((JsonObject) reorderedItemsFromClient - .get(index)).getNumber("nodeid"); - items.add(nodeIdToItems.get(nodeIdFromClient)); - } + public List getItems() { return items; } - private static JsonArray getSectionItems(JsonArray items, - int sectionNodeId) { - for (int rootLevelIdx = 0; rootLevelIdx < items - .length(); rootLevelIdx++) { - JsonObject item = items.get(rootLevelIdx); - int itemNodeId = (int) item.getNumber("nodeid"); - if (sectionNodeId == itemNodeId) { - JsonObject sectionObj = items.get(rootLevelIdx); - return sectionObj.getArray("items"); - } - } - return null; + /** + * Returns the section that contains the moved item, or an empty optional if + * the item is a direct child of the dashboard + * + * @return the section that contains the moved item, or an empty optional if + * the item is a direct child of the dashboard + */ + public Optional getSection() { + return Optional.ofNullable(section); } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java index 8702a08ecfe..e270d45554b 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemRemovedEvent.java @@ -8,13 +8,11 @@ */ package com.vaadin.flow.component.dashboard; -import java.util.Objects; +import java.util.List; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEvent; import com.vaadin.flow.component.ComponentEventListener; -import com.vaadin.flow.component.DomEvent; -import com.vaadin.flow.component.EventData; /** * Widget or section removed event of {@link Dashboard}. @@ -22,10 +20,11 @@ * @author Vaadin Ltd. * @see Dashboard#addItemRemovedListener(ComponentEventListener) */ -@DomEvent("dashboard-item-removed") public class DashboardItemRemovedEvent extends ComponentEvent { - private final Component removedItem; + private final Component item; + + private final List items; /** * Creates a dashboard item removed event. @@ -33,13 +32,18 @@ public class DashboardItemRemovedEvent extends ComponentEvent { * @param source * Dashboard that contains the item that was removed * @param fromClient - * true if the event originated from the client - * side, false otherwise + * {@code true} if the event originated from the client side, + * {@code false} otherwise + * @param item + * The removed item + * @param items + * The root level items of the dashboard */ public DashboardItemRemovedEvent(Dashboard source, boolean fromClient, - @EventData("event.detail.item.nodeid") int nodeId) { + Component item, List items) { super(source, fromClient); - this.removedItem = getRemovedItem(source, nodeId); + this.item = item; + this.items = items; } /** @@ -47,22 +51,16 @@ public DashboardItemRemovedEvent(Dashboard source, boolean fromClient, * * @return the removed item */ - public Component getRemovedItem() { - return removedItem; + public Component getItem() { + return item; } - private static Component getRemovedItem(Dashboard dashboard, int nodeId) { - return dashboard.getChildren().map(item -> { - if (nodeId == item.getElement().getNode().getId()) { - return item; - } - if (item instanceof DashboardSection section) { - return section.getWidgets().stream() - .filter(sectionItem -> nodeId == sectionItem - .getElement().getNode().getId()) - .findAny().orElse(null); - } - return null; - }).filter(Objects::nonNull).findAny().orElse(null); + /** + * Returns the root level items of the dashboard + * + * @return the root level items of the dashboard + */ + public List getItems() { + return items; } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemResizedEvent.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemResizedEvent.java index 0d66ee06a57..ba34d7976e9 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemResizedEvent.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/main/java/com/vaadin/flow/component/dashboard/DashboardItemResizedEvent.java @@ -8,10 +8,11 @@ */ package com.vaadin.flow.component.dashboard; +import java.util.List; + +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEvent; import com.vaadin.flow.component.ComponentEventListener; -import com.vaadin.flow.component.DomEvent; -import com.vaadin.flow.component.EventData; /** * Widget resized event of {@link Dashboard}. @@ -19,14 +20,11 @@ * @author Vaadin Ltd. * @see Dashboard#addItemResizedListener(ComponentEventListener) */ -@DomEvent("dashboard-item-resized") public class DashboardItemResizedEvent extends ComponentEvent { - private final DashboardWidget resizedWidget; - - private final int colspan; + private final DashboardWidget item; - private final int rowspan; + private final List items; /** * Creates a dashboard item resized event. @@ -34,25 +32,18 @@ public class DashboardItemResizedEvent extends ComponentEvent { * @param source * Dashboard that contains the widget that was resized * @param fromClient - * true if the event originated from the client - * side, false otherwise - * @param nodeId - * Node ID the resized widget - * @param colspan - * New colspan of the resized widget - * @param rowspan - * New rowspan of the resized widget + * {@code true} if the event originated from the client side, + * {@code false} otherwise + * @param item + * The resized widget + * @param items + * The root level items of the dashboard */ public DashboardItemResizedEvent(Dashboard source, boolean fromClient, - @EventData("event.detail.item.nodeid") int nodeId, - @EventData("event.detail.item.colspan") int colspan, - @EventData("event.detail.item.rowspan") int rowspan) { + DashboardWidget item, List items) { super(source, fromClient); - this.resizedWidget = source.getWidgets().stream() - .filter(child -> nodeId == child.getElement().getNode().getId()) - .findAny().orElse(null); - this.colspan = colspan; - this.rowspan = rowspan; + this.item = item; + this.items = items; } /** @@ -60,25 +51,16 @@ public DashboardItemResizedEvent(Dashboard source, boolean fromClient, * * @return the resized widget */ - public DashboardWidget getResizedWidget() { - return resizedWidget; - } - - /** - * Returns the new colspan of the resized item - * - * @return new colspan of the resized item - */ - public int getColspan() { - return colspan; + public DashboardWidget getItem() { + return item; } /** - * Returns the new rowspan of the resized item + * Returns the root level items of the dashboard * - * @return new rowspan of the resized item + * @return the root level items of the dashboard */ - public int getRowspan() { - return rowspan; + public List getItems() { + return items; } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java index 0adf255ed5d..35f036a0641 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragReorderTest.java @@ -10,17 +10,21 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import com.vaadin.flow.component.ComponentUtil; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dashboard.Dashboard; -import com.vaadin.flow.component.dashboard.DashboardItemMovedEvent; import com.vaadin.flow.component.dashboard.DashboardSection; import com.vaadin.flow.component.dashboard.DashboardWidget; +import com.vaadin.flow.dom.DomEvent; +import com.vaadin.flow.internal.nodefeature.ElementListenerMap; import elemental.json.Json; import elemental.json.JsonArray; @@ -73,19 +77,124 @@ public void reorderWidgetInSectionToSamePosition_orderIsNotUpdated() { @Test public void setDashboardNotEditable_reorderWidget_orderIsNotUpdated() { dashboard.setEditable(false); + int movedWidgetNodeId = dashboard.getChildren().toList().get(0) + .getElement().getNode().getId(); List expectedRootLevelNodeIds = getRootLevelNodeIds(); reorderRootLevelItem(0, 1); - fireItemMovedEvent(); + fireItemMovedEvent(movedWidgetNodeId); Assert.assertEquals(expectedRootLevelNodeIds, getRootLevelNodeIds()); } - private void fireItemMovedEvent() { - fireItemMovedEvent(null); + @Test + public void reorderWidget_eventCorrectlyFired() { + int initialIndex = 0; + int finalIndex = 1; + Component movedItem = dashboard.getChildren().toList() + .get(initialIndex); + int movedItemNodeId = movedItem.getElement().getNode().getId(); + List expectedItems = dashboard.getChildren() + .collect(Collectors.toCollection(ArrayList::new)); + expectedItems.add(finalIndex, expectedItems.remove(initialIndex)); + Runnable itemMoveAction = () -> { + reorderRootLevelItem(initialIndex, finalIndex); + fireItemMovedEvent(movedItemNodeId); + }; + assertEventCorrectlyFired(itemMoveAction, 1, movedItem, expectedItems, + null); + } + + @Test + public void reorderSection_eventCorrectlyFired() { + int initialIndex = 2; + int finalIndex = 1; + Component movedItem = dashboard.getChildren().toList() + .get(initialIndex); + int movedItemNodeId = movedItem.getElement().getNode().getId(); + List expectedItems = dashboard.getChildren() + .collect(Collectors.toCollection(ArrayList::new)); + expectedItems.add(finalIndex, expectedItems.remove(initialIndex)); + Runnable itemMoveAction = () -> { + reorderRootLevelItem(initialIndex, finalIndex); + fireItemMovedEvent(movedItemNodeId); + }; + assertEventCorrectlyFired(itemMoveAction, 1, movedItem, expectedItems, + null); + } + + @Test + public void reorderWidgetInSection_eventCorrectlyFired() { + int sectionIndex = 2; + int initialIndex = 0; + int finalIndex = 1; + List expectedItems = dashboard.getChildren().toList(); + DashboardSection section = (DashboardSection) expectedItems + .get(sectionIndex); + int sectionNodeId = section.getElement().getNode().getId(); + Component movedItem = section.getWidgets().get(initialIndex); + int movedItemNodeId = movedItem.getElement().getNode().getId(); + Runnable itemMoveAction = () -> { + reorderSectionWidget(sectionIndex, initialIndex, finalIndex); + fireItemMovedEvent(movedItemNodeId, sectionNodeId); + }; + assertEventCorrectlyFired(itemMoveAction, 1, movedItem, expectedItems, + section); } - private void fireItemMovedEvent(Integer sectionNodeId) { - ComponentUtil.fireEvent(dashboard, new DashboardItemMovedEvent( - dashboard, false, itemsArray, sectionNodeId)); + @Test + public void setDashboardNotEditable_reorderWidget_eventNotFired() { + dashboard.setEditable(false); + int initialIndex = 0; + int finalIndex = 1; + Component movedItem = dashboard.getChildren().toList() + .get(initialIndex); + int movedItemNodeId = movedItem.getElement().getNode().getId(); + Runnable itemMoveAction = () -> { + reorderRootLevelItem(initialIndex, finalIndex); + fireItemMovedEvent(movedItemNodeId); + }; + assertEventCorrectlyFired(itemMoveAction, 0, null, null, null); + } + + private void assertEventCorrectlyFired(Runnable itemMoveAction, + int expectedListenerInvokedCount, Component expectedItem, + List expectedItems, DashboardSection expectedSection) { + AtomicInteger listenerInvokedCount = new AtomicInteger(0); + AtomicReference eventItem = new AtomicReference<>(); + AtomicReference> eventItems = new AtomicReference<>(); + AtomicReference> eventSection = new AtomicReference<>(); + dashboard.addItemMovedListener(e -> { + listenerInvokedCount.incrementAndGet(); + eventItem.set(e.getItem()); + eventItems.set(e.getItems()); + eventSection.set(e.getSection()); + e.unregisterListener(); + }); + itemMoveAction.run(); + Assert.assertEquals(expectedListenerInvokedCount, + listenerInvokedCount.get()); + if (expectedListenerInvokedCount > 0) { + Assert.assertEquals(expectedItem, eventItem.get()); + Assert.assertEquals(expectedItems, eventItems.get()); + Assert.assertEquals(Optional.ofNullable(expectedSection), + eventSection.get()); + } + } + + private void fireItemMovedEvent(int itemNodeId) { + fireItemMovedEvent(itemNodeId, null); + } + + private void fireItemMovedEvent(int itemNodeId, Integer sectionNodeId) { + JsonObject eventData = Json.createObject(); + eventData.put("event.detail.item", itemNodeId); + eventData.put("event.detail.items", itemsArray); + if (sectionNodeId != null) { + eventData.put("event.detail.section", sectionNodeId); + } + DomEvent itemMovedDomEvent = new DomEvent(dashboard.getElement(), + "dashboard-item-moved-flow", eventData); + dashboard.getElement().getNode().getFeature(ElementListenerMap.class) + .fireEvent(itemMovedDomEvent); } private List getSectionWidgetNodeIds(int sectionIndex) { @@ -136,21 +245,26 @@ private void reorderRootLevelItem(int initialIndex, int finalIndex) { private void assertSectionWidgetReorder(int sectionIndex, int initialIndex, int finalIndex) { - int sectionNodeId = dashboard.getChildren().toList().get(sectionIndex) + DashboardSection section = (DashboardSection) dashboard.getChildren() + .toList().get(sectionIndex); + int sectionNodeId = section.getElement().getNode().getId(); + int movedWidgetNodeId = section.getWidgets().get(initialIndex) .getElement().getNode().getId(); reorderSectionWidget(sectionIndex, initialIndex, finalIndex); List expectedSectionWidgetNodeIds = getExpectedSectionWidgetNodeIds( sectionIndex, initialIndex, finalIndex); - fireItemMovedEvent(sectionNodeId); + fireItemMovedEvent(movedWidgetNodeId, sectionNodeId); Assert.assertEquals(expectedSectionWidgetNodeIds, getSectionWidgetNodeIds(sectionIndex)); } private void assertRootLevelItemReorder(int initialIndex, int finalIndex) { + int movedItemNodeId = dashboard.getChildren().toList().get(initialIndex) + .getElement().getNode().getId(); reorderRootLevelItem(initialIndex, finalIndex); List expectedRootLevelNodeIds = getExpectedRootLevelItemNodeIds( initialIndex, finalIndex); - fireItemMovedEvent(); + fireItemMovedEvent(movedItemNodeId); Assert.assertEquals(expectedRootLevelNodeIds, getRootLevelNodeIds()); } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeTest.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeTest.java index 5345f7947d3..7a396a7e4bb 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeTest.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardDragResizeTest.java @@ -8,15 +8,23 @@ */ package com.vaadin.flow.component.dashboard.tests; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import com.vaadin.flow.component.ComponentUtil; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dashboard.Dashboard; -import com.vaadin.flow.component.dashboard.DashboardItemResizedEvent; import com.vaadin.flow.component.dashboard.DashboardSection; import com.vaadin.flow.component.dashboard.DashboardWidget; +import com.vaadin.flow.dom.DomEvent; +import com.vaadin.flow.internal.nodefeature.ElementListenerMap; + +import elemental.json.Json; +import elemental.json.JsonObject; public class DashboardDragResizeTest extends DashboardTestBase { private Dashboard dashboard; @@ -73,6 +81,53 @@ public void setDashboardNotEditable_resizeWidget_sizeIsNotUpdated() { Assert.assertEquals(1, widgetToResize.getRowspan()); } + @Test + public void resizeWidget_eventCorrectlyFired() { + DashboardWidget resizedWidget = (DashboardWidget) dashboard + .getChildren().toList().get(0); + assertEventCorrectlyFired(resizedWidget, 1, resizedWidget, + dashboard.getChildren().toList()); + } + + @Test + public void resizeWidgetInSection_eventCorrectlyFired() { + DashboardSection section = (DashboardSection) dashboard.getChildren() + .toList().get(1); + DashboardWidget resizedWidget = section.getWidgets().get(0); + assertEventCorrectlyFired(resizedWidget, 1, resizedWidget, + dashboard.getChildren().toList()); + } + + @Test + public void setDashboardNotEditable_resizeWidget_eventNotFired() { + dashboard.setEditable(false); + DashboardWidget resizedWidget = (DashboardWidget) dashboard + .getChildren().toList().get(0); + assertEventCorrectlyFired(resizedWidget, 0, null, null); + } + + private void assertEventCorrectlyFired(DashboardWidget widgetToResize, + int expectedListenerInvokedCount, Component expectedResizedWidget, + List expectedItems) { + AtomicInteger listenerInvokedCount = new AtomicInteger(0); + AtomicReference eventResizedWidget = new AtomicReference<>(); + AtomicReference> eventItems = new AtomicReference<>(); + dashboard.addItemResizedListener(e -> { + listenerInvokedCount.incrementAndGet(); + eventResizedWidget.set(e.getItem()); + eventItems.set(e.getItems()); + e.unregisterListener(); + }); + fireItemResizedEvent(widgetToResize, 2, 2); + Assert.assertEquals(expectedListenerInvokedCount, + listenerInvokedCount.get()); + if (expectedListenerInvokedCount > 0) { + Assert.assertEquals(expectedResizedWidget, + eventResizedWidget.get()); + Assert.assertEquals(expectedItems, eventItems.get()); + } + } + private void assertWidgetResized(int widgetIndexToResize, int targetColspan, int targetRowspan) { DashboardWidget widgetToResize = dashboard.getWidgets() @@ -89,9 +144,14 @@ private void assertWidgetResized(int widgetIndexToResize, int targetColspan, private void fireItemResizedEvent(DashboardWidget widget, int targetColspan, int targetRowspan) { - ComponentUtil.fireEvent(dashboard, - new DashboardItemResizedEvent(dashboard, false, - widget.getElement().getNode().getId(), targetColspan, - targetRowspan)); + JsonObject eventData = Json.createObject(); + eventData.put("event.detail.item.nodeid", + widget.getElement().getNode().getId()); + eventData.put("event.detail.item.rowspan", targetRowspan); + eventData.put("event.detail.item.colspan", targetColspan); + DomEvent itemResizedDomEvent = new DomEvent(dashboard.getElement(), + "dashboard-item-resized", eventData); + dashboard.getElement().getNode().getFeature(ElementListenerMap.class) + .fireEvent(itemResizedDomEvent); } } diff --git a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardTest.java b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardTest.java index 3c50d285c7a..aed06c51307 100644 --- a/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardTest.java +++ b/vaadin-dashboard-flow-parent/vaadin-dashboard-flow/src/test/java/com/vaadin/flow/component/dashboard/tests/DashboardTest.java @@ -8,19 +8,27 @@ */ package com.vaadin.flow.component.dashboard.tests; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import com.vaadin.flow.component.ComponentUtil; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dashboard.Dashboard; -import com.vaadin.flow.component.dashboard.DashboardItemRemovedEvent; import com.vaadin.flow.component.dashboard.DashboardSection; import com.vaadin.flow.component.dashboard.DashboardWidget; import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.dom.DomEvent; +import com.vaadin.flow.internal.nodefeature.ElementListenerMap; + +import elemental.json.Json; +import elemental.json.JsonObject; public class DashboardTest extends DashboardTestBase { private Dashboard dashboard; @@ -852,8 +860,84 @@ public void setDashboardEditable_removeWidget_widgetIsRemoved() { Assert.assertFalse(actualNodeIds.contains(nodeIdToBeRemoved)); } + @Test + public void setDashboardEditable_removeWidget_eventCorrectlyFired() { + dashboard.setEditable(true); + DashboardWidget widget = new DashboardWidget(); + dashboard.add(widget); + fakeClientCommunication(); + int removedWidgetNodeId = widget.getElement().getNode().getId(); + List expectedItems = dashboard.getChildren() + .collect(Collectors.toCollection(ArrayList::new)); + expectedItems.remove(widget); + assertItemRemoveEventCorrectlyFired(removedWidgetNodeId, 1, widget, + expectedItems); + } + + @Test + public void setDashboardEditable_removeSection_eventCorrectlyFired() { + dashboard.setEditable(true); + DashboardSection section = dashboard.addSection(); + fakeClientCommunication(); + int removedSectionNodeId = section.getElement().getNode().getId(); + List expectedItems = dashboard.getChildren() + .collect(Collectors.toCollection(ArrayList::new)); + expectedItems.remove(section); + assertItemRemoveEventCorrectlyFired(removedSectionNodeId, 1, section, + expectedItems); + } + + @Test + public void setDashboardEditable_removeWidgetInSection_eventCorrectlyFired() { + dashboard.setEditable(true); + DashboardSection section = dashboard.addSection(); + DashboardWidget widget = new DashboardWidget(); + section.add(widget); + fakeClientCommunication(); + int removedWidgetNodeId = widget.getElement().getNode().getId(); + List expectedItems = dashboard.getChildren() + .collect(Collectors.toCollection(ArrayList::new)); + expectedItems.remove(widget); + assertItemRemoveEventCorrectlyFired(removedWidgetNodeId, 1, widget, + expectedItems); + } + + @Test + public void dashboardNotEditable_removeWidget_eventNotFired() { + DashboardWidget widget = new DashboardWidget(); + dashboard.add(widget); + fakeClientCommunication(); + int removedWidgetNodeId = widget.getElement().getNode().getId(); + assertItemRemoveEventCorrectlyFired(removedWidgetNodeId, 0, null, null); + } + + private void assertItemRemoveEventCorrectlyFired(int nodeIdToRemove, + int expectedListenerInvokedCount, Component expectedRemovedItem, + List expectedItems) { + AtomicInteger listenerInvokedCount = new AtomicInteger(0); + AtomicReference eventRemovedItem = new AtomicReference<>(); + AtomicReference> eventItems = new AtomicReference<>(); + dashboard.addItemRemovedListener(e -> { + listenerInvokedCount.incrementAndGet(); + eventRemovedItem.set(e.getItem()); + eventItems.set(e.getItems()); + e.unregisterListener(); + }); + fireItemRemovedEvent(nodeIdToRemove); + Assert.assertEquals(expectedListenerInvokedCount, + listenerInvokedCount.get()); + if (expectedListenerInvokedCount > 0) { + Assert.assertEquals(expectedRemovedItem, eventRemovedItem.get()); + Assert.assertEquals(expectedItems, eventItems.get()); + } + } + private void fireItemRemovedEvent(int nodeId) { - ComponentUtil.fireEvent(dashboard, - new DashboardItemRemovedEvent(dashboard, false, nodeId)); + JsonObject eventData = Json.createObject(); + eventData.put("event.detail.item.nodeid", nodeId); + DomEvent itemRemovedDomEvent = new DomEvent(dashboard.getElement(), + "dashboard-item-removed", eventData); + dashboard.getElement().getNode().getFeature(ElementListenerMap.class) + .fireEvent(itemRemovedDomEvent); } }