import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;
+import com.vaadin.client.BrowserInfo;
import com.vaadin.client.DeferredWorker;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.widget.grid.events.ScrollEvent;
* set either <code>overflow-x</code> or <code>overflow-y</code> to "
* <code>scroll</code>" in the scrollbar's direction.
* <p>
- * This is an IE8 workaround, since it doesn't always show scrollbars with
- * <code>overflow: auto</code> enabled.
+ * This method is an IE8 workaround, since it doesn't always show scrollbars
+ * with <code>overflow: auto</code> enabled.
+ * <p>
+ * Firefox on the other hand loses pending scroll events when the scrollbar
+ * is hidden, so the event must be fired manually.
+ * <p>
+ * When IE8 support is dropped, this should really be simplified.
*/
protected void forceScrollbar(boolean enable) {
if (enable) {
root.getStyle().clearDisplay();
} else {
+ if (BrowserInfo.get().isFirefox()) {
+ /*
+ * This is related to the Firefox workaround in setScrollSize
+ * for setScrollPos(0)
+ */
+ scrollEventFirer.scheduleEvent();
+ }
+
root.getStyle().setDisplay(Display.NONE);
}
internalForceScrollbar(enable);
* This needs to be made step-by-step because IE8 flat-out refuses to
* fire a scroll event when the scroll size becomes smaller than the
* offset size. All other browser need to suffer alongside.
+ *
+ * This really should be changed to not use any temporary scroll
+ * handlers at all once IE8 support is dropped, like now done only for
+ * Firefox.
*/
boolean newScrollSizeIsSmallerThanOffsetSize = px <= getOffsetSize();
boolean scrollSizeBecomesSmallerThanOffsetSize = showsScrollHandle()
&& newScrollSizeIsSmallerThanOffsetSize;
if (scrollSizeBecomesSmallerThanOffsetSize && getScrollPos() != 0) {
+ /*
+ * For whatever reason, Firefox loses the scroll event in this case
+ * and the onscroll handler is never called (happens when reducing
+ * size from 1000 items to 1 while being scrolled a bit down, see
+ * #19802). Based on the comment above, only IE8 should really use
+ * 'delayedSizeSet'
+ */
+ boolean delayedSizeSet = !BrowserInfo.get().isFirefox();
// must be a field because Java insists.
- scrollSizeTemporaryScrollHandler = addScrollHandler(new ScrollHandler() {
- @Override
- public void onScroll(ScrollEvent event) {
- setScrollSizeNow(px);
- }
- });
+ if (delayedSizeSet) {
+ scrollSizeTemporaryScrollHandler = addScrollHandler(
+ new ScrollHandler() {
+ @Override
+ public void onScroll(ScrollEvent event) {
+ setScrollSizeNow(px);
+ }
+ });
+ }
setScrollPos(0);
+ if (!delayedSizeSet) {
+ setScrollSizeNow(px);
+ }
} else {
setScrollSizeNow(px);
}
--- /dev/null
+package com.vaadin.tests.components.grid;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.data.Container.Filterable;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.filter.SimpleStringFilter;
+import com.vaadin.event.FieldEvents.TextChangeEvent;
+import com.vaadin.event.FieldEvents.TextChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Grid;
+import com.vaadin.ui.Grid.HeaderRow;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.themes.ValoTheme;
+
+@Theme("valo")
+public class GridApplyFilterWhenScrolledDown extends UI {
+
+ Grid grid = new Grid();
+
+ @Override
+ protected void init(VaadinRequest vaadinRequest) {
+
+ grid.addColumn("Name", String.class);
+
+ HeaderRow appendHeaderRow = grid.appendHeaderRow();
+ TextField filter = getColumnFilter("Name");
+ appendHeaderRow.getCell("Name").setComponent(filter);
+
+ for (int i = 0; i < 1000; i++) {
+ Item addItem = grid.getContainerDataSource().addItem(i);
+ addItem.getItemProperty("Name").setValue("Name " + i);
+
+ }
+
+ Item addItem = grid.getContainerDataSource().addItem(1000);
+ addItem.getItemProperty("Name").setValue("Test");
+
+ grid.scrollToStart();
+ setContent(grid);
+ }
+
+ private TextField getColumnFilter(final Object columnId) {
+ TextField filter = new TextField();
+ filter.setWidth("100%");
+ filter.addStyleName(ValoTheme.TEXTFIELD_TINY);
+ filter.addTextChangeListener(new TextChangeListener() {
+ SimpleStringFilter filter = null;
+
+ @Override
+ public void textChange(TextChangeEvent event) {
+ Filterable f = (Filterable) grid.getContainerDataSource();
+ if (filter != null) {
+ f.removeContainerFilter(filter);
+ }
+ filter = new SimpleStringFilter(columnId, event.getText(), true,
+ true);
+ f.addContainerFilter(filter);
+ }
+ });
+ return filter;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package com.vaadin.tests.components.grid;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.elements.GridElement;
+import com.vaadin.testbench.elements.TextFieldElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class GridApplyFilterWhenScrolledDownTest extends MultiBrowserTest {
+
+ @Test
+ public void scrolledCorrectly() throws InterruptedException {
+ openTestURL();
+ final GridElement grid = $(GridElement.class).first();
+ grid.scrollToRow(50);
+ $(TextFieldElement.class).first().setValue("Test");
+ final TestBenchElement gridBody = grid.getBody();
+ // Can't use element API because it scrolls
+ waitUntil(new ExpectedCondition<Boolean>() {
+
+ @Override
+ public Boolean apply(WebDriver input) {
+ return gridBody.findElements(By.className("v-grid-row"))
+ .size() == 1;
+ }
+ });
+ WebElement cell = gridBody.findElements(By.className("v-grid-cell"))
+ .get(0);
+ Assert.assertEquals("Test", cell.getText());
+
+ Assert.assertTrue(
+ grid.getVerticalScroller().getSize().getHeight() < 100);
+ }
+}