]> source.dussan.org Git - vaadin-framework.git/commitdiff
UI scroll position can be given programmatically (#9952) 78/378/5
authorLeif Åstrand <leif@vaadin.com>
Thu, 29 Nov 2012 14:36:27 +0000 (16:36 +0200)
committerVaadin Code Review <review@vaadin.com>
Fri, 30 Nov 2012 07:42:46 +0000 (07:42 +0000)
Change-Id: Icef0858ee495abcacab7823f7f8fc6044abd64dc

client/src/com/vaadin/client/ui/VUI.java
client/src/com/vaadin/client/ui/ui/UIConnector.java
server/src/com/vaadin/ui/UI.java
shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java [new file with mode: 0644]
shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.html [new file with mode: 0644]
uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.java [new file with mode: 0644]

index 688c60bca10a0361a8056bf4ddf62dee1d885b40..cbfbda813e10b9f5c965d64420edd1acd835da3b 100644 (file)
@@ -20,6 +20,9 @@ import java.util.ArrayList;
 
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.HasScrollHandlers;
+import com.google.gwt.event.dom.client.ScrollEvent;
+import com.google.gwt.event.dom.client.ScrollHandler;
 import com.google.gwt.event.logical.shared.HasResizeHandlers;
 import com.google.gwt.event.logical.shared.ResizeEvent;
 import com.google.gwt.event.logical.shared.ResizeHandler;
@@ -49,7 +52,7 @@ import com.vaadin.shared.ui.ui.UIConstants;
  */
 public class VUI extends SimplePanel implements ResizeHandler,
         Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable,
-        HasResizeHandlers {
+        HasResizeHandlers, HasScrollHandlers {
 
     private static int MONITOR_PARENT_TIMER_INTERVAL = 1000;
 
@@ -94,18 +97,9 @@ public class VUI extends SimplePanel implements ResizeHandler,
     /** stored height of parent for embedded application auto-resize */
     private int parentHeight;
 
-    /** For internal use only. May be removed or replaced in the future. */
-    public int scrollTop;
-
-    /** For internal use only. May be removed or replaced in the future. */
-    public int scrollLeft;
-
     /** For internal use only. May be removed or replaced in the future. */
     public boolean rendering;
 
-    /** For internal use only. May be removed or replaced in the future. */
-    public boolean scrollable;
-
     /** For internal use only. May be removed or replaced in the future. */
     public boolean immediate;
 
@@ -350,26 +344,6 @@ public class VUI extends SimplePanel implements ResizeHandler,
         if (type == Event.ONKEYDOWN && actionHandler != null) {
             actionHandler.handleKeyboardEvent(event);
             return;
-        } else if (scrollable && type == Event.ONSCROLL) {
-            updateScrollPosition();
-        }
-    }
-
-    /**
-     * Updates scroll position from DOM and saves variables to server.
-     */
-    private void updateScrollPosition() {
-        int oldTop = scrollTop;
-        int oldLeft = scrollLeft;
-        scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
-        scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
-        if (connection != null && !rendering) {
-            if (oldTop != scrollTop) {
-                connection.updateVariable(id, "scrollTop", scrollTop, false);
-            }
-            if (oldLeft != scrollLeft) {
-                connection.updateVariable(id, "scrollLeft", scrollLeft, false);
-            }
         }
     }
 
@@ -478,4 +452,9 @@ public class VUI extends SimplePanel implements ResizeHandler,
         return addHandler(resizeHandler, ResizeEvent.getType());
     }
 
+    @Override
+    public HandlerRegistration addScrollHandler(ScrollHandler scrollHandler) {
+        return addHandler(scrollHandler, ScrollEvent.getType());
+    }
+
 }
index 1d2c830ea6aa04fd16bc426032ad4da759c8452b..a297a89b8e7380560af5c044bfc6d4f840b4240b 100644 (file)
@@ -23,10 +23,13 @@ import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.dom.client.Style;
 import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.event.dom.client.ScrollEvent;
+import com.google.gwt.event.dom.client.ScrollHandler;
 import com.google.gwt.event.logical.shared.ResizeEvent;
 import com.google.gwt.event.logical.shared.ResizeHandler;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.Window;
@@ -56,6 +59,7 @@ import com.vaadin.shared.ui.ComponentStateUtil;
 import com.vaadin.shared.ui.Connect;
 import com.vaadin.shared.ui.Connect.LoadStyle;
 import com.vaadin.shared.ui.ui.PageClientRpc;
+import com.vaadin.shared.ui.ui.ScrollClientRpc;
 import com.vaadin.shared.ui.ui.UIConstants;
 import com.vaadin.shared.ui.ui.UIServerRpc;
 import com.vaadin.shared.ui.ui.UIState;
@@ -85,6 +89,17 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
                 com.google.gwt.user.client.Window.setTitle(title);
             }
         });
+        registerRpc(ScrollClientRpc.class, new ScrollClientRpc() {
+            @Override
+            public void setScrollTop(int scrollTop) {
+                getWidget().getElement().setScrollTop(scrollTop);
+            }
+
+            @Override
+            public void setScrollLeft(int scrollLeft) {
+                getWidget().getElement().setScrollLeft(scrollLeft);
+            }
+        });
         getWidget().addResizeHandler(new ResizeHandler() {
             @Override
             public void onResize(ResizeEvent event) {
@@ -96,6 +111,24 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
                 }
             }
         });
+        getWidget().addScrollHandler(new ScrollHandler() {
+            private int lastSentScrollTop = Integer.MAX_VALUE;
+            private int lastSentScrollLeft = Integer.MAX_VALUE;
+
+            @Override
+            public void onScroll(ScrollEvent event) {
+                Element element = getWidget().getElement();
+                int newScrollTop = element.getScrollTop();
+                int newScrollLeft = element.getScrollLeft();
+                if (newScrollTop != lastSentScrollTop
+                        || newScrollLeft != lastSentScrollLeft) {
+                    lastSentScrollTop = newScrollTop;
+                    lastSentScrollLeft = newScrollLeft;
+                    getRpcProxy(UIServerRpc.class).scroll(newScrollTop,
+                            newScrollLeft);
+                }
+            }
+        });
     }
 
     @Override
@@ -244,19 +277,6 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
             Window.addResizeHandler(getWidget());
         }
 
-        // finally set scroll position from UIDL
-        if (uidl.hasVariable("scrollTop")) {
-            getWidget().scrollable = true;
-            getWidget().scrollTop = uidl.getIntVariable("scrollTop");
-            DOM.setElementPropertyInt(getWidget().getElement(), "scrollTop",
-                    getWidget().scrollTop);
-            getWidget().scrollLeft = uidl.getIntVariable("scrollLeft");
-            DOM.setElementPropertyInt(getWidget().getElement(), "scrollLeft",
-                    getWidget().scrollLeft);
-        } else {
-            getWidget().scrollable = false;
-        }
-
         if (uidl.hasAttribute("scrollTo")) {
             final ComponentConnector connector = (ComponentConnector) uidl
                     .getPaintableAttribute("scrollTo", getConnection());
index 55f756010ed2889b75b76c09ca17145946d071d9..b45aedb8e104301b08c7a37757ae3d2e51c3aba2 100644 (file)
@@ -39,6 +39,7 @@ import com.vaadin.server.VaadinServlet;
 import com.vaadin.server.VaadinSession;
 import com.vaadin.shared.EventId;
 import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.ui.ui.ScrollClientRpc;
 import com.vaadin.shared.ui.ui.UIConstants;
 import com.vaadin.shared.ui.ui.UIServerRpc;
 import com.vaadin.shared.ui.ui.UIState;
@@ -114,6 +115,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements
 
     private Page page = new Page(this);
 
+    /**
+     * Scroll Y position.
+     */
+    private int scrollTop = 0;
+
+    /**
+     * Scroll X position
+     */
+    private int scrollLeft = 0;
+
     private UIServerRpc rpc = new UIServerRpc() {
         @Override
         public void click(MouseEventDetails mouseDetails) {
@@ -126,6 +137,12 @@ public abstract class UI extends AbstractSingleComponentContainer implements
             // TODO We're not doing anything with the view dimensions
             getPage().updateBrowserWindowSize(windowWidth, windowHeight);
         }
+
+        @Override
+        public void scroll(int scrollTop, int scrollLeft) {
+            UI.this.scrollTop = scrollTop;
+            UI.this.scrollLeft = scrollLeft;
+        }
     };
 
     /**
@@ -560,8 +577,44 @@ public abstract class UI extends AbstractSingleComponentContainer implements
         return CurrentInstance.get(UI.class);
     }
 
+    /**
+     * Set top offset to which the UI should scroll to.
+     * 
+     * @param scrollTop
+     */
     public void setScrollTop(int scrollTop) {
-        throw new RuntimeException("Not yet implemented");
+        if (scrollTop < 0) {
+            throw new IllegalArgumentException(
+                    "Scroll offset must be at least 0");
+        }
+        if (this.scrollTop != scrollTop) {
+            this.scrollTop = scrollTop;
+            getRpcProxy(ScrollClientRpc.class).setScrollTop(scrollTop);
+        }
+    }
+
+    public int getScrollTop() {
+        return scrollTop;
+    }
+
+    /**
+     * Set left offset to which the UI should scroll to.
+     * 
+     * @param scrollLeft
+     */
+    public void setScrollLeft(int scrollLeft) {
+        if (scrollLeft < 0) {
+            throw new IllegalArgumentException(
+                    "Scroll offset must be at least 0");
+        }
+        if (this.scrollLeft != scrollLeft) {
+            this.scrollLeft = scrollLeft;
+            getRpcProxy(ScrollClientRpc.class).setScrollLeft(scrollLeft);
+        }
+    }
+
+    public int getScrollLeft() {
+        return scrollLeft;
     }
 
     @Override
diff --git a/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java b/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java
new file mode 100644 (file)
index 0000000..26ec7f2
--- /dev/null
@@ -0,0 +1,26 @@
+/* 
+ * Copyright 2011 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.shared.ui.ui;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+public interface ScrollClientRpc extends ClientRpc {
+
+    public void setScrollTop(int scrollTop);
+
+    public void setScrollLeft(int scrollLeft);
+}
index 11a400bbe0d7046fd7d1e9e5f34b2fd964aa7afc..a89b70c8cd235418045506a74177fcc19e44fa25 100644 (file)
@@ -23,4 +23,7 @@ public interface UIServerRpc extends ClickRpc, ServerRpc {
     @Delayed(lastOnly = true)
     public void resize(int viewWidth, int viewHeight, int windowWidth,
             int windowHeight);
+
+    @Delayed(lastOnly = true)
+    public void scroll(int scrollTop, int scrollLeft);
 }
\ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.html b/uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.html
new file mode 100644 (file)
index 0000000..b5326e4
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>UIScrollTest</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">UIScrollTest</td></tr>
+</thead><tbody>
+<tr>
+       <td>open</td>
+       <td>/run/com.vaadin.tests.components.uitest.UIScrollTest?restartApplication</td>
+       <td></td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestscomponentsuitestUIScrollTest::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<tr>
+       <td>screenCapture</td>
+       <td></td>
+       <td>Halfway_down_button</td>
+</tr>
+<tr>
+       <td>scroll</td>
+       <td>vaadin=runcomvaadintestscomponentsuitestUIScrollTest::</td>
+       <td>1020</td>
+</tr>
+<tr>
+       <td>pause</td>
+       <td>300</td>
+       <td></td>
+</tr>
+<tr>
+       <td>click</td>
+       <td>vaadin=runcomvaadintestscomponentsuitestUIScrollTest::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+       <td></td>
+</tr>
+<tr>
+       <td>assertText</td>
+       <td>//div[@id='runcomvaadintestscomponentsuitestUIScrollTest-1797389287-overlays']/div</td>
+       <td>Scrolled to 1020 px</td>
+</tr>
+<tr>
+       <td>closeNotification</td>
+       <td>//div[@id='runcomvaadintestscomponentsuitestUIScrollTest-1797389287-overlays']/div</td>
+       <td>0,0</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.java b/uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.java
new file mode 100644 (file)
index 0000000..66b6ef9
--- /dev/null
@@ -0,0 +1,44 @@
+package com.vaadin.tests.components.uitest;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.UI;
+
+public class UIScrollTest extends TestBase {
+
+    @Override
+    protected void setup() {
+        // Set layout to high enough to get scroll.
+        getLayout().setHeight("2250px");
+        addComponent(new Button("scoll to 1000px", new Button.ClickListener() {
+
+            @Override
+            public void buttonClick(ClickEvent event) {
+                UI.getCurrent().setScrollTop(1000);
+            }
+        }));
+        addComponent(new Button(
+                "This button is halfway down. Click to report scroll position.",
+                new Button.ClickListener() {
+                    @Override
+                    public void buttonClick(ClickEvent event) {
+                        Notification.show("Scrolled to "
+                                + event.getButton().getUI().getScrollTop()
+                                + " px");
+                    }
+                }));
+    }
+
+    @Override
+    protected String getDescription() {
+        return "Windows can be programmatically scrolled";
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        return 9952;
+    }
+
+}