Ver código fonte

Add scrollbars to ComboBox suggestion popup if low on screen estate (#11929)

Change-Id: I8563f1e2cfc66ca89399590401fd77ec67e50e82
tags/7.3.0.beta1
Antti Tanhuanpää 10 anos atrás
pai
commit
ede8fbaad0

+ 30
- 15
client/src/com/vaadin/client/ui/VFilterSelect.java Ver arquivo

@@ -30,6 +30,7 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -212,6 +213,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
private final Element down = DOM.createDiv();
private final Element status = DOM.createDiv();

private int desiredHeight = -1;

private boolean isPagingEnabled = true;

private long lastAutoClosed;
@@ -228,6 +231,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
debug("VFS.SP: constructor()");
setOwner(VFilterSelect.this);
menu = new SuggestionMenu();
menu.getElement().getStyle().setOverflowY(Overflow.AUTO);
setWidget(menu);

getElement().getStyle().setZIndex(Z_INDEX);
@@ -550,16 +554,12 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
public void setPosition(int offsetWidth, int offsetHeight) {
debug("VFS.SP: setPosition()");

int top = -1;
int left = -1;
int top = getPopupTop();
int left = getPopupLeft();

// reset menu size and retrieve its "natural" size
menu.setHeight("");
if (currentPage > 0) {
// fix height to avoid height change when getting to last page
menu.fixHeightTo(pageLength);
if (desiredHeight < 0) {
desiredHeight = offsetHeight;
}
offsetHeight = getOffsetHeight();

final int desiredWidth = getMainWidth();
Element menuFirstChild = menu.getElement().getFirstChildElement();
@@ -585,16 +585,20 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
getContainerElement().getStyle().setWidth(rootWidth, Unit.PX);
}

if (offsetHeight + getPopupTop() > Window.getClientHeight()
+ Window.getScrollTop()) {
final int spaceAvailableBelow = Window.getClientHeight()
- (top - Window.getScrollTop());
final int spaceAvailableAbove = top - Window.getScrollTop()
- VFilterSelect.this.getOffsetHeight();
if (spaceAvailableBelow < desiredHeight
&& spaceAvailableBelow < spaceAvailableAbove) {
// popup on top of input instead
top = getPopupTop() - offsetHeight
- VFilterSelect.this.getOffsetHeight();
top -= desiredHeight + VFilterSelect.this.getOffsetHeight();
offsetHeight = desiredHeight;
if (top < 0) {
offsetHeight += top;
top = 0;
}
} else {
top = getPopupTop();
/*
* Take popup top margin into account. getPopupTop() returns the
* top value including the margin but the value we give must not
@@ -602,6 +606,19 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*/
int topMargin = (top - topPosition);
top -= topMargin;
offsetHeight = Math.min(desiredHeight, spaceAvailableBelow);
}

/*
* Resize popup and menu if calculated height doesn't match the
* actual height
*/
if (getOffsetHeight() != offsetHeight) {
int menuHeight = offsetHeight - up.getOffsetHeight()
- down.getOffsetHeight() - status.getOffsetHeight();
menu.setHeight(menuHeight + "px");
getContainerElement().getStyle().setHeight(offsetHeight,
Unit.PX);
}

// fetch real width (mac FF bugs here due GWT popups overflow:auto )
@@ -614,8 +631,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (left < 0) {
left = 0;
}
} else {
left = getPopupLeft();
}
setPopupPosition(left, top);
}

+ 64
- 0
uitest/src/com/vaadin/tests/components/combobox/ComboBoxOnSmallScreen.java Ver arquivo

@@ -0,0 +1,64 @@
/*
* 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.Alignment;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.VerticalLayout;

/**
* Test UI for issue #11929 where ComboBox suggestion popup hides the ComboBox
* itself obscuring the text input field.
*
* @author Vaadin Ltd
*/
public class ComboBoxOnSmallScreen extends AbstractTestUI {

private static final String PID = "captionPID";

@Override
protected void setup(VaadinRequest request) {
addComponents(createComboBox(), createComboBox());
VerticalLayout vl = getLayout();
vl.setHeight(300, Unit.PIXELS);
vl.setComponentAlignment(vl.getComponent(1), Alignment.BOTTOM_LEFT);
}

@Override
protected String getTestDescription() {
return "Combobox hides what you are typing on small screen";
}

@Override
protected Integer getTicketNumber() {
return 11929;
}

private ComboBox createComboBox() {
ComboBox cb = new ComboBox();
cb.addContainerProperty(PID, String.class, "");
cb.setItemCaptionPropertyId(PID);

for (int i = 1; i < 21; ++i) {
final String v = "Item #" + i;
cb.getItem(cb.addItem()).getItemProperty(PID).setValue(v);
}

return cb;
}
}

+ 108
- 0
uitest/src/com/vaadin/tests/components/combobox/ComboBoxOnSmallScreenTest.java Ver arquivo

@@ -0,0 +1,108 @@
/*
* 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 static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver.Window;
import org.openqa.selenium.WebElement;

import com.vaadin.client.ui.VFilterSelect;
import com.vaadin.testbench.elements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;

/**
* ComboBox suggestion popup should not obscure the text input box.
*
* @author Vaadin Ltd
*/
public class ComboBoxOnSmallScreenTest extends MultiBrowserTest {

private static final Dimension TARGETSIZE = new Dimension(600, 300);
private static final String POPUPCLASSNAME = VFilterSelect.CLASSNAME
+ "-suggestpopup";

@Override
public void setup() throws Exception {
super.setup();

openTestURL();

getWindow().setSize(TARGETSIZE);
}

@Test
public void testUpperSuggestionPopupOverlayPosition() {
ComboBoxElement cb = getComboBoxAndOpenPopup(0);
assertOverlayPosition(cb, getPopup());
}

@Test
public void testUpperSuggestionPopupOverlaySize() {
ComboBoxElement cb = getComboBoxAndOpenPopup(0);
assertOverlaySize(cb, getPopup());
}

@Test
public void testLowerSuggestionPopupOverlayPosition() {
ComboBoxElement cb = getComboBoxAndOpenPopup(1);
assertOverlayPosition(cb, getPopup());
}

@Test
public void testLowerSuggestionPopupOverlaySize() {
ComboBoxElement cb = getComboBoxAndOpenPopup(1);
assertOverlaySize(cb, getPopup());
}

private void assertOverlayPosition(WebElement combobox, WebElement popup) {
final int popupTop = popup.getLocation().y;
final int popupBottom = popupTop + popup.getSize().getHeight();
final int cbTop = combobox.getLocation().y;
final int cbBottom = cbTop + combobox.getSize().getHeight();

assertThat("Popup overlay does not overlap with the textbox",
popupTop >= cbBottom || popupBottom <= cbTop, is(true));
}

private void assertOverlaySize(WebElement combobox, WebElement popup) {
final int popupTop = popup.getLocation().y;
final int popupBottom = popupTop + popup.getSize().getHeight();
final int rootHeight = findElement(By.tagName("body")).getSize().height;

assertThat("Popup overlay inside the viewport", popupTop < 0
|| popupBottom > rootHeight, is(false));
}

private ComboBoxElement getComboBoxAndOpenPopup(int comboboxIndex) {
ComboBoxElement cb = $(ComboBoxElement.class).get(comboboxIndex);
cb.openPopup();
return cb;
}

private WebElement getPopup() {
return findElement(By.className(POPUPCLASSNAME));
}

private Window getWindow() {
return getDriver().manage().window();
}

}

Carregando…
Cancelar
Salvar