From c20e2e9c1aefb99eae2bd69df02e1324c7abe479 Mon Sep 17 00:00:00 2001 From: Tatu Lund Date: Tue, 19 Nov 2019 11:04:44 +0200 Subject: [PATCH] Fixing issue with TwinColSelect not correctly retaining visible selection (#11799) There is a bug in TwinColSelect loging, it retains selection by indexes not by values after being sorted when new item has been added. This is a fixed by changing updateListBox method to retain the selection as it is being called after selection is being done. Fixes: #11287 --- .../com/vaadin/client/ui/VTwinColSelect.java | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/client/src/main/java/com/vaadin/client/ui/VTwinColSelect.java b/client/src/main/java/com/vaadin/client/ui/VTwinColSelect.java index 6cbdb944ec..8618f9b52d 100644 --- a/client/src/main/java/com/vaadin/client/ui/VTwinColSelect.java +++ b/client/src/main/java/com/vaadin/client/ui/VTwinColSelect.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.stream.Collectors; +import com.google.gwt.core.client.Scheduler; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.event.dom.client.ClickEvent; @@ -37,6 +38,7 @@ import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; @@ -80,6 +82,7 @@ public class VTwinColSelect extends Composite implements MultiSelectWidget, private static final int VISIBLE_COUNT = 10; private static final int DEFAULT_COLUMN_COUNT = 10; + private static int scheduledScrollToItem = -1; private final DoubleClickListBox optionsListBox; @@ -327,15 +330,28 @@ public class VTwinColSelect extends Composite implements MultiSelectWidget, private static void updateListBox(ListBox listBox, List options) { + List selected = new ArrayList(); + // Retain right visible selection, see #11287 + for (int i = 0; i < listBox.getItemCount(); ++i) { + if (listBox.isItemSelected(i)) { + selected.add(listBox.getItemText(i)); + } + } for (int i = 0; i < options.size(); i++) { final JsonObject item = options.get(i); // reuse existing option if possible + String caption = MultiSelectWidget.getCaption(item); if (i < listBox.getItemCount()) { - listBox.setItemText(i, MultiSelectWidget.getCaption(item)); + listBox.setItemText(i, caption); listBox.setValue(i, MultiSelectWidget.getKey(item)); } else { - listBox.addItem(MultiSelectWidget.getCaption(item), - MultiSelectWidget.getKey(item)); + listBox.addItem(caption, MultiSelectWidget.getKey(item)); + } + boolean isSelected = selected.contains(caption); + listBox.setItemSelected(i, isSelected); + if (isSelected) { + // Ensure that last selected item is visible + scrollToView(listBox,i); } } // remove extra @@ -344,6 +360,19 @@ public class VTwinColSelect extends Composite implements MultiSelectWidget, } } + private static void scrollToView(ListBox listBox, int i) { + if (scheduledScrollToItem == -1) { + scheduledScrollToItem = i; + Scheduler.get().scheduleDeferred(() -> { + Element el = (Element) listBox.getElement().getChild(scheduledScrollToItem); + el.scrollIntoView(); + scheduledScrollToItem = -1; + }); + } else { + scheduledScrollToItem = i; + } + } + private static boolean[] getSelectionBitmap(ListBox listBox) { final boolean[] selectedIndexes = new boolean[listBox.getItemCount()]; for (int i = 0; i < listBox.getItemCount(); i++) { -- 2.39.5