From: Leif Åstrand Date: Thu, 29 Nov 2012 14:36:27 +0000 (+0200) Subject: UI scroll position can be given programmatically (#9952) X-Git-Tag: 7.0.0.beta11~100 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fchanges%2F78%2F378%2F5;p=vaadin-framework.git UI scroll position can be given programmatically (#9952) Change-Id: Icef0858ee495abcacab7823f7f8fc6044abd64dc --- diff --git a/client/src/com/vaadin/client/ui/VUI.java b/client/src/com/vaadin/client/ui/VUI.java index 688c60bca1..cbfbda813e 100644 --- a/client/src/com/vaadin/client/ui/VUI.java +++ b/client/src/com/vaadin/client/ui/VUI.java @@ -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()); + } + } diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 1d2c830ea6..a297a89b8e 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -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()); diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 55f756010e..b45aedb8e1 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -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 index 0000000000..26ec7f2de2 --- /dev/null +++ b/shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java @@ -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); +} diff --git a/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java b/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java index 11a400bbe0..a89b70c8cd 100644 --- a/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java @@ -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 index 0000000000..b5326e4660 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.html @@ -0,0 +1,57 @@ + + + + + + +UIScrollTest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
UIScrollTest
open/run/com.vaadin.tests.components.uitest.UIScrollTest?restartApplication
clickvaadin=runcomvaadintestscomponentsuitestUIScrollTest::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]
screenCaptureHalfway_down_button
scrollvaadin=runcomvaadintestscomponentsuitestUIScrollTest::1020
pause300
clickvaadin=runcomvaadintestscomponentsuitestUIScrollTest::/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VVerticalLayout[0]/VOrderedLayout$Slot[1]/VButton[0]/domChild[0]/domChild[0]
assertText//div[@id='runcomvaadintestscomponentsuitestUIScrollTest-1797389287-overlays']/divScrolled to 1020 px
closeNotification//div[@id='runcomvaadintestscomponentsuitestUIScrollTest-1797389287-overlays']/div0,0
+ + 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 index 0000000000..66b6ef90b1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.java @@ -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; + } + +}