Extract code which focuses on item after changing the page. Deferring this method allows to update the list of items before focusing.
Change-Id: I7d249c2abbd5c24ca2d798736e483f2b7dfa59f1
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
/**
* Client side implementation of the Select component.
- *
+ *
* TODO needs major refactoring (to be extensible etc)
*/
@SuppressWarnings("deprecation")
/**
* Constructor
- *
+ *
* @param uidl
* The UIDL recieved from the server
*/
/**
* Get the option key which represents the item on the server side.
- *
+ *
* @return The key of the item
*/
public String getOptionKey() {
/**
* Get the URI of the icon. Used when constructing the displayed option.
- *
+ *
* @return
*/
public String getIconUri() {
/**
* Shows the popup where the user can see the filtered options
- *
+ *
* @param currentSuggestions
* The filtered suggestions
* @param currentPage
* correctly. This issue manifests when a Combobox is placed in
* another popupView which also needs to calculate the absoluteTop()
* to position itself. #9768
+ *
+ * After deferring the showSuggestions method, a problem with
+ * navigating in the combo box occurs. Because of that the method
+ * navigateItemAfterPageChange in ComboBoxConnector class, which
+ * navigates to the exact item after page was changed also was
+ * marked as deferred. #11333
*/
final SuggestionPopup popup = this;
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
/**
* Should the next page button be visible to the user?
- *
+ *
* @param active
*/
private void setNextButtonActive(boolean active) {
/**
* Should the previous page button be visible to the user
- *
+ *
* @param active
*/
private void setPrevButtonActive(boolean active) {
* amount of items are visible at a time and a scrollbar or buttons are
* visible to change page. If paging is turned of then all options are
* rendered into the popup menu.
- *
+ *
* @param paging
* Should the paging be turned on?
*/
/**
* Was the popup just closed?
- *
+ *
* @return true if popup was just closed
*/
public boolean isJustClosed() {
/**
* Updates style names in suggestion popup to help theme building.
- *
+ *
* @param uidl
* UIDL for the whole combo box
* @param componentState
/**
* Sets the suggestions rendered in the menu
- *
+ *
* @param suggestions
* The suggestions to be rendered in the menu
*/
/**
* TextBox variant used as input element for filter selects, which prevents
* selecting text when disabled.
- *
+ *
* @since 7.1.5
*/
public class FilterSelectTextBox extends TextBox {
* It is invoked during the Constructor and should only be overridden if a
* custom TextBox shall be used. The overriding method cannot use any
* instance variables.
- *
+ *
* @since 7.1.5
* @return TextBox instance used by this VFilterSelect
*/
* instance. It is invoked during the Constructor and should only be
* overridden if a custom SuggestionPopup shall be used. The overriding
* method cannot use any instance variables.
- *
+ *
* @since 7.1.5
* @return SuggestionPopup instance used by this VFilterSelect
*/
/**
* Does the Select have more pages?
- *
+ *
* @return true if a next page exists, else false if the current page is the
* last page
*/
/**
* Filters the options at a certain page. Uses the text box input as a
* filter
- *
+ *
* @param page
* The page which items are to be filtered
*/
/**
* Filters the options at certain page using the given filter
- *
+ *
* @param page
* The page to filter
* @param filter
/**
* Filters the options at certain page using the given filter
- *
+ *
* @param page
* The page to filter
* @param filter
/**
* Sets the text in the text box.
- *
+ *
* @param text
* the text to set in the text box
*/
* shown in the text box if nothing has been entered.
* <p>
* For internal use only. May be removed or replaced in the future.
- *
+ *
* @param text
* The text the text box should contain.
*/
/**
* Triggered when a suggestion is selected
- *
+ *
* @param suggestion
* The suggestion that just got selected.
*/
/**
* Sets the icon URI of the selected item. The icon is shown on the left
* side of the item caption text. Set the URI to null to remove the icon.
- *
+ *
* @param iconUri
* The URI of the icon
*/
/**
* Triggered when a key is pressed in the text box
- *
+ *
* @param event
* The KeyDownEvent
*/
/**
* Triggered when a key was pressed in the suggestion popup.
- *
+ *
* @param event
* The KeyDownEvent of the key
*/
/**
* Triggered when a key was depressed
- *
+ *
* @param event
* The KeyUpEvent of the key depressed
*/
/**
* Get the width of the select in pixels where the text area and icon has
* been included.
- *
+ *
* @return The width in pixels
*/
private int getMainWidth() {
/**
* Handles special behavior of the mouse down event
- *
+ *
* @param event
*/
private void handleMouseDownEvent(Event event) {
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* 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
import java.util.Iterator;
import java.util.List;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
/*
* (non-Javadoc)
- *
+ *
* @see com.vaadin.client.Paintable#updateFromUIDL(com.vaadin.client.UIDL,
* com.vaadin.client.ApplicationConnection)
*/
if (!getWidget().popupOpenerClicked
&& getWidget().selectPopupItemWhenResponseIsReceived != VFilterSelect.Select.NONE) {
// we're paging w/ arrows
- if (getWidget().selectPopupItemWhenResponseIsReceived == VFilterSelect.Select.LAST) {
- getWidget().suggestionPopup.menu.selectLastItem();
- } else {
- getWidget().suggestionPopup.menu.selectFirstItem();
- }
-
- // This is used for paging so we update the keyboard selection
- // variable as well.
- MenuItem activeMenuItem = getWidget().suggestionPopup.menu
- .getSelectedItem();
- getWidget().suggestionPopup.menu
- .setKeyboardSelectedItem(activeMenuItem);
-
- // Update text field to contain the correct text
- getWidget().setTextboxText(activeMenuItem.getText());
- getWidget().tb.setSelectionRange(
- getWidget().lastFilter.length(),
- activeMenuItem.getText().length()
- - getWidget().lastFilter.length());
-
- getWidget().selectPopupItemWhenResponseIsReceived = VFilterSelect.Select.NONE; // reset
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ navigateItemAfterPageChange();
+ }
+ });
}
+
if (getWidget().updateSelectionWhenReponseIsReceived) {
getWidget().suggestionPopup.menu
.doPostFilterSelectedItemAction();
getWidget().initDone = true;
}
+ /*
+ * This method navigates to the proper item in the combobox page. This
+ * should be executed after setSuggestions() method which is called from
+ * vFilterSelect.showSuggestions(). ShowSuggestions() method builds the page
+ * content. As far as setSuggestions() method is called as deferred,
+ * navigateItemAfterPageChange method should be also be called as deferred.
+ * #11333
+ */
+ private void navigateItemAfterPageChange() {
+ if (getWidget().selectPopupItemWhenResponseIsReceived == VFilterSelect.Select.LAST) {
+ getWidget().suggestionPopup.menu.selectLastItem();
+ } else {
+ getWidget().suggestionPopup.menu.selectFirstItem();
+ }
+
+ // This is used for paging so we update the keyboard selection
+ // variable as well.
+ MenuItem activeMenuItem = getWidget().suggestionPopup.menu
+ .getSelectedItem();
+ getWidget().suggestionPopup.menu
+ .setKeyboardSelectedItem(activeMenuItem);
+
+ // Update text field to contain the correct text
+ getWidget().setTextboxText(activeMenuItem.getText());
+ getWidget().tb.setSelectionRange(
+ getWidget().lastFilter.length(),
+ activeMenuItem.getText().length()
+ - getWidget().lastFilter.length());
+
+ getWidget().selectPopupItemWhenResponseIsReceived = VFilterSelect.Select.NONE; // reset
+ }
+
private void performSelection(String selectedKey) {
// some item selected
for (FilterSelectSuggestion suggestion : getWidget().currentSuggestions) {
--- /dev/null
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * 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 com.vaadin.tests.components.combobox;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.AbstractLayout;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Test UI verifying navigating in combobox via arrow keys.
+ */
+public class ComboBoxScrollingWithArrows extends AbstractTestUI {
+ final String DESCRIPTION = "When positioned on last item in the page and press downArrow key - should open new page and set focus on the first item.";
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server.
+ * VaadinRequest)
+ */
+ @Override
+ protected void setup(VaadinRequest request) {
+ VerticalLayout layout = new VerticalLayout();
+ addComponent(layout);
+ addComboBox(layout);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription()
+ */
+ @Override
+ protected String getTestDescription() {
+ return DESCRIPTION;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber()
+ */
+ @Override
+ protected Integer getTicketNumber() {
+ return 11333;
+ }
+
+ private void addComboBox(AbstractLayout layout) {
+ ComboBox box = new ComboBox();
+ for (int i = 0; i < 100; i++) {
+ box.addItem("item " + i);
+ }
+ box.setPageLength(10);
+ box.setNullSelectionAllowed(false);
+ layout.addComponent(box);
+ }
+}
--- /dev/null
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * 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 com.vaadin.tests.components.combobox;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * When pressed down key, while positioned on the last item - should show next
+ * page and focus on the first item of the next page.
+ */
+public class ComboBoxScrollingWithArrowsTest extends MultiBrowserTest {
+
+ @Before
+ public void openURL() {
+ openTestURL();
+ }
+
+ @Test
+ public void scrollDownArrowKeyTest() throws InterruptedException {
+ final int ITEMS_PER_PAGE = 10;
+ // Selenium is used instead of TestBench4, because there is no method to
+ // access the popup of the combobox
+ // The method ComboBoxElement.openPopup() opens the popup, but doesn't
+ // provide any way to access the popup and send keys to it.
+ // Ticket #13756
+ WebElement dropDownComboBox = driver.findElement(By
+ .className("v-filterselect-input"));
+ // opens Lookup
+ dropDownComboBox.sendKeys(Keys.DOWN);
+ // go to the last item and then one more
+ for (int i = 0; i < ITEMS_PER_PAGE + 1; i++) {
+ dropDownComboBox.sendKeys(Keys.DOWN);
+ }
+ String expected = "item " + ITEMS_PER_PAGE;// item 10
+
+ List<WebElement> items = driver.findElements(By
+ .className("gwt-MenuItem-selected"));
+ String actual = items.get(0).getText();
+ Assert.assertEquals(expected, actual);
+ }
+
+ @Test
+ public void scrollUpArrowKeyTest() throws InterruptedException {
+ final int ITEMS_PER_PAGE = 10;
+ WebElement dropDownComboBox = driver.findElement(By
+ .className("v-filterselect-input"));
+ // opens Lookup
+ dropDownComboBox.sendKeys(Keys.DOWN);
+ // go to the last item and then one more
+ for (int i = 0; i < ITEMS_PER_PAGE + 1; i++) {
+ dropDownComboBox.sendKeys(Keys.DOWN);
+ }
+ // move to one item up
+ dropDownComboBox.sendKeys(Keys.UP);
+ String expected = "item " + (ITEMS_PER_PAGE - 1);// item 9
+ List<WebElement> items = driver.findElements(By
+ .className("gwt-MenuItem-selected"));
+ String actual = items.get(0).getText();
+ Assert.assertEquals(expected, actual);
+ }
+}