Browse Source

UI scroll position can be given programmatically (#9952)

Change-Id: Icef0858ee495abcacab7823f7f8fc6044abd64dc
tags/7.0.0.beta11
Leif Åstrand 11 years ago
parent
commit
9dd665b56e

+ 9
- 30
client/src/com/vaadin/client/ui/VUI.java View 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());
}

}

+ 33
- 13
client/src/com/vaadin/client/ui/ui/UIConnector.java View 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());

+ 54
- 1
server/src/com/vaadin/ui/UI.java View 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

+ 26
- 0
shared/src/com/vaadin/shared/ui/ui/ScrollClientRpc.java View File

@@ -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);
}

+ 3
- 0
shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java View 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);
}

+ 57
- 0
uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.html View File

@@ -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>

+ 44
- 0
uitest/src/com/vaadin/tests/components/uitest/UIScrollTest.java View File

@@ -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;
}

}

Loading…
Cancel
Save