]> source.dussan.org Git - vaadin-framework.git/commitdiff
Fixed scroll jump by using native focusing in IE (#15294)
authorJohannes Tuikkala <johannes@vaadin.com>
Thu, 5 Mar 2015 11:32:33 +0000 (13:32 +0200)
committerLeif Åstrand <leif@vaadin.com>
Thu, 26 Mar 2015 14:16:52 +0000 (16:16 +0200)
Change-Id: I412ba219f31567ebba019b7d6ce4db4af9be9363

WebContent/statictestfiles/TableInIframeRowClickScrollJumpTest.html [new file with mode: 0644]
client/src/com/vaadin/client/ui/FocusableScrollPanel.java
uitest/src/com/vaadin/tests/components/table/TableBlurFocus.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/components/table/TableBlurFocusTest.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/components/table/TableInIframeRowClickScrollJumpTest.java [new file with mode: 0644]

diff --git a/WebContent/statictestfiles/TableInIframeRowClickScrollJumpTest.html b/WebContent/statictestfiles/TableInIframeRowClickScrollJumpTest.html
new file mode 100644 (file)
index 0000000..dfddbdb
--- /dev/null
@@ -0,0 +1,12 @@
+<html>\r
+<head>\r
+<title>IEJumpTest</title>\r
+</head>\r
+<!-- This is for testing Vaadin UI in iFrame (test class TableInIframeRowClickScrollJumpTest, for ticket #15294 -->\r
+<body>\r
+       <div style="font-size: 4px">test div</div>\r
+       <iframe id="test-iframe-0" src="/run/com.vaadin.tests.components.table.TableBlurFocus" width="100%" height="2000px" style="visibility: visible;">\r
+       </iframe>\r
+</body>\r
+\r
+</html>
\ No newline at end of file
index 475c8f8074e8499ef59568b20be8cf98e3d82d19..9dd9c176756d4881c4cdc2fc0b0a1cfb849a8c6d 100644 (file)
@@ -48,9 +48,11 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
         Style style = getElement().getStyle();
         style.setProperty("zoom", "1");
         style.setPosition(Position.RELATIVE);
+        browserInfo = BrowserInfo.get();
     }
 
     private DivElement focusElement;
+    private BrowserInfo browserInfo;
 
     public FocusableScrollPanel(boolean useFakeFocusElement) {
         this();
@@ -72,6 +74,12 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
                 style.setPosition(Position.FIXED);
                 style.setTop(0, Unit.PX);
                 style.setLeft(0, Unit.PX);
+                if (browserInfo.isIE()) {
+                    // for #15294: artificially hide little bit more the
+                    // focusElement, otherwise IE will make the window to scroll
+                    // into it when focused
+                    style.setLeft(-999, Unit.PX);
+                }
                 getElement().appendChild(focusElement);
                 /* Sink from focusElemet too as focusa and blur don't bubble */
                 DOM.sinkEvents(focusElement, Event.FOCUSEVENTS);
diff --git a/uitest/src/com/vaadin/tests/components/table/TableBlurFocus.java b/uitest/src/com/vaadin/tests/components/table/TableBlurFocus.java
new file mode 100644 (file)
index 0000000..d95b406
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * 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.table;
+
+import java.util.Map;
+
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.Table;
+
+/**
+ * Tests that previously focused component's blur event happens before any
+ * variable changes in the focused Table.
+ * 
+ * @author Vaadin Ltd
+ */
+public class TableBlurFocus extends AbstractTestUIWithLog {
+
+    enum Columns {
+        COLUMN1, COLUMN2, COLUMN3, COLUMN4, COLUMN5
+    }
+
+    private int count = 0;
+    private Button focusButton;
+
+    @Override
+    protected void setup(VaadinRequest request) {
+        System.out
+                .println("TableBlurFocus/TableInIframeRowClickScrollJumpTest");
+        Button button = new Button("click to focus");
+        button.addFocusListener(new FocusListener() {
+
+            @Override
+            public void focus(FocusEvent event) {
+                log("focus");
+            }
+        });
+        button.addBlurListener(new BlurListener() {
+
+            @Override
+            public void blur(BlurEvent event) {
+                log("blur");
+            }
+        });
+        final Button scrollButton = new Button(
+                "focus lowest button to scroll down");
+        scrollButton.setId("scroll-button");
+        scrollButton.addClickListener(new ClickListener() {
+            @Override
+            public void buttonClick(ClickEvent event) {
+                focusButton.focus();
+            }
+        });
+
+        Label spacerLabel = new Label("spacer");
+        spacerLabel.setHeight("300px");
+
+        addComponent(button);
+        addComponent(scrollButton);
+        addComponent(createTable());
+        addComponent(spacerLabel);
+        addComponent(focusButton = new Button("for focus"));
+        focusButton.setId("focus-button");
+        focusButton.addFocusListener(new FocusListener() {
+            @Override
+            public void focus(FocusEvent event) {
+                focusButton.setCaption("focused");
+            }
+        });
+    }
+
+    private Table createTable() {
+        Table table = new Table() {
+            @Override
+            public void changeVariables(Object source,
+                    Map<String, Object> variables) {
+                log("variable change");
+                super.changeVariables(source, variables);
+            }
+        };
+        table.setSelectable(true);
+        table.setImmediate(true);
+
+        table.addContainerProperty(Columns.COLUMN1, String.class, " ");
+        table.addContainerProperty(Columns.COLUMN2, Label.class, null);
+        table.addContainerProperty(Columns.COLUMN3, Button.class, null);
+        table.addContainerProperty(Columns.COLUMN4, String.class, " ");
+        table.setColumnCollapsingAllowed(true);
+        table.setColumnCollapsible(Columns.COLUMN4, true);
+        table.setColumnCollapsed(Columns.COLUMN4, true);
+        table.setSortEnabled(true);
+        table.setFooterVisible(true);
+        table.setPageLength(14);
+        table.addGeneratedColumn(Columns.COLUMN5, new Table.ColumnGenerator() {
+
+            @Override
+            public Object generateCell(Table source, Object itemId,
+                    Object columnId) {
+                return "Generated";
+            }
+        });
+
+        table.setColumnHeader(Columns.COLUMN1, "Column");
+        for (int x = 0; x < 120; x++) {
+            final Label buttonLabel = new Label("Not clicked");
+            Button button = new Button("Click me?", new Button.ClickListener() {
+
+                @Override
+                public void buttonClick(Button.ClickEvent event) {
+                    ++count;
+                    buttonLabel.setValue("Clicked " + count + " times");
+                    Notification.show("Clicked!");
+                }
+            });
+            table.addItem(new Object[] { "entryString" + x, buttonLabel,
+                    button, " " }, "entryID" + x);
+        }
+        return table;
+    }
+
+    @Override
+    protected String getTestDescription() {
+        return "Click button to focus, then click Table header. Blur event should arrive before the next variable change.";
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        return 15294;
+    }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableBlurFocusTest.java b/uitest/src/com/vaadin/tests/components/table/TableBlurFocusTest.java
new file mode 100644 (file)
index 0000000..e5d07ab
--- /dev/null
@@ -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.table;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.TableElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class TableBlurFocusTest extends MultiBrowserTest {
+
+    @Test
+    public void testBlurAndFocus() throws InterruptedException {
+        openTestURL();
+        waitForElementPresent(By.className("v-button"));
+
+        assertAnyLogText("1. variable change");
+        assertEquals("Unexpected column header,", "COLUMN2",
+                $(TableElement.class).first().getHeaderCell(1).getCaption());
+        assertEquals("Unexpected button caption,", "click to focus",
+                $(ButtonElement.class).first().getCaption());
+
+        $(ButtonElement.class).first().click();
+        assertAnyLogText("2. focus", "3. focus");
+
+        $(TableElement.class).first().getHeaderCell(1).click();
+        assertAnyLogText("3. blur", "4. blur");
+    }
+
+    private void assertAnyLogText(String... texts) {
+        assertThat(String.format(
+                "Correct log text was not found, expected any of %s",
+                Arrays.asList(texts)), logContainsAnyText(texts));
+    }
+
+    private boolean logContainsAnyText(String... texts) {
+        for (String text : texts) {
+            if (logContainsText(text)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableInIframeRowClickScrollJumpTest.java b/uitest/src/com/vaadin/tests/components/table/TableInIframeRowClickScrollJumpTest.java
new file mode 100644 (file)
index 0000000..074958d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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.table;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.TableElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * For testing that UI scroll does not jump back to up when: 1. UI is in iframe
+ * 2. the window scrolled down 3. and table is clicked
+ * 
+ * @since
+ * @author Vaadin Ltd
+ */
+public class TableInIframeRowClickScrollJumpTest extends MultiBrowserTest {
+
+    private static final String TEST_URL = "statictestfiles/TableInIframeRowClickScrollJumpTest.html";
+
+    @Test
+    public void testRowClicking_WhenScrolledDown_shouldMaintainScrollPosition()
+            throws InterruptedException {
+        System.out.println(">>>" + getBaseURL() + TEST_URL);
+
+        driver.get(getUrl());
+
+        // using non-standard way because of iframe
+        sleep(4000);
+
+        // make sure we are in the "main content"
+        driver.switchTo().defaultContent();
+        sleep(2000);
+        switchIntoIframe();
+
+        // using non-standard way because of iframe
+        waitForElementVisible(By.id("scroll-button"));
+
+        ButtonElement scrollbutton = $(ButtonElement.class).id("scroll-button");
+        scrollbutton.click();
+
+        // using non-standard way because of iframe
+        sleep(1000);
+
+        Long scrollPosition = getWindowsScrollPosition();
+
+        assertThat("Scroll position should be greater than 100 (it was "
+                + scrollPosition + ")", scrollPosition > 100);
+
+        TableElement table = $(TableElement.class).first();
+        table.getRow(13).getCell(0).click();
+
+        // using non-standard way because of iframe
+        sleep(1000);
+
+        Long scrollPosition2 = getWindowsScrollPosition();
+
+        assertThat("Scroll position should stay about the same. Old was "
+                + scrollPosition + " and new one " + scrollPosition2,
+                Math.abs(scrollPosition - scrollPosition2) < 10);
+    }
+
+    private String getUrl() {
+        String url;
+        // using non-standard way because of iframe
+        if (getBaseURL().charAt(getBaseURL().length() - 1) == '/') {
+            url = getBaseURL() + TEST_URL;
+        } else {
+            // this one is for gerrit's teamcity :(
+            url = getBaseURL() + '/' + TEST_URL;
+        }
+        return url;
+    }
+
+    public void switchIntoIframe() {
+        List<WebElement> frames = driver.findElements(By.tagName("iframe"));
+        assertThat("No frames was found", frames.size() > 0);
+        driver.switchTo().frame(frames.get(0));
+    }
+
+    private Long getWindowsScrollPosition() {
+        // measure scroll pos in the main window
+        driver.switchTo().defaultContent();
+
+        JavascriptExecutor executor = (JavascriptExecutor) driver;
+        Long value = (Long) executor
+                .executeScript("if (window.pageYOffset) return window.pageYOffset;else if (window.document.documentElement.scrollTop) return window.document.documentElement.scrollTop;else return window.document.body.scrollTop;");
+
+        // back to the iframe
+        switchIntoIframe();
+
+        return value;
+    }
+
+    @Override
+    // using non-standard way because of iframe
+    protected void closeApplication() {
+        if (driver != null) {
+            try {
+                driver.get(getUrl() + "?closeApplication");
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}