aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/terminal/gwt/client
diff options
context:
space:
mode:
authorHenri Sara <hesara@vaadin.com>2012-06-20 17:38:17 +0300
committerHenri Sara <hesara@vaadin.com>2012-06-20 17:38:17 +0300
commitd83a57c7facca417e4e92cacaa64ee9b6dbe4597 (patch)
tree22d127d79edea56a6c20bdd43b6bc24bb008a1da /src/com/vaadin/terminal/gwt/client
parent93e9eaf7abfad12d200e9f1805630b7b04daf7e2 (diff)
parent0f8f9d32e0584743c858afeec12e57dedf0a5f71 (diff)
downloadvaadin-framework-d83a57c7facca417e4e92cacaa64ee9b6dbe4597.tar.gz
vaadin-framework-d83a57c7facca417e4e92cacaa64ee9b6dbe4597.zip
Merge branch 'master' into gwt
Diffstat (limited to 'src/com/vaadin/terminal/gwt/client')
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java25
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConnection.java38
-rw-r--r--src/com/vaadin/terminal/gwt/client/BrowserInfo.java20
-rw-r--r--src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java372
-rw-r--r--src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java32
-rw-r--r--src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java36
-rw-r--r--src/com/vaadin/terminal/gwt/client/JavascriptConnectorHelper.java205
-rw-r--r--src/com/vaadin/terminal/gwt/client/JavascriptExtension.java33
-rw-r--r--src/com/vaadin/terminal/gwt/client/Util.java16
-rw-r--r--src/com/vaadin/terminal/gwt/client/WidgetSet.java6
-rw-r--r--src/com/vaadin/terminal/gwt/client/communication/HasJavaScriptConnectorHelper.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/communication/HasJavascriptConnectorHelper.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/communication/RpcManager.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/extensions/AbstractExtensionConnector.java27
-rw-r--r--src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/ExecuteJavaScriptRpc.java11
-rw-r--r--src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java119
-rw-r--r--src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerState.java (renamed from src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerState.java)2
-rw-r--r--src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerConnector.java78
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java104
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java15
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java5
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java42
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java37
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/JavaScriptWidget.java (renamed from src/com/vaadin/terminal/gwt/client/ui/JavascriptWidget.java)6
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/JavascriptComponentConnector.java60
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java111
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/button/VButton.java42
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java37
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/AcceptCriterion.java33
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java21
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VAcceptAll.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VAnd.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VContainsDataFlavor.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VLazyInitItemIdentifiers.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VNot.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VOr.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VServerAccept.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VTargetDetailIs.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java1
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java3
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java10
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/form/VForm.java5
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java19
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java33
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/PageClientRpc.java13
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java15
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java223
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java7
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java36
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java207
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java242
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java15
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java40
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java44
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java4
64 files changed, 1834 insertions, 713 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
index 244f310c1a..960b0a8b0e 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
@@ -18,6 +18,7 @@ import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;
public class ApplicationConfiguration implements EntryPoint {
@@ -346,6 +347,7 @@ public class ApplicationConfiguration implements EntryPoint {
*/
public static void startApplication(final String applicationId) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+
public void execute() {
ApplicationConfiguration appConf = getConfigFromDOM(applicationId);
ApplicationConnection a = GWT
@@ -568,6 +570,7 @@ public class ApplicationConfiguration implements EntryPoint {
* GWT hosted mode.
*/
GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+
public void onUncaughtException(Throwable e) {
/*
* Note in case of null console (without ?debug) we eat
@@ -602,12 +605,15 @@ public class ApplicationConfiguration implements EntryPoint {
*
* @return true if client side is currently been debugged
*/
- public native static boolean isDebugMode()
+ public static boolean isDebugMode() {
+ return isDebugAvailable()
+ && Window.Location.getParameter("debug") != null;
+ }
+
+ private native static boolean isDebugAvailable()
/*-{
if($wnd.vaadin.debug) {
- var parameters = $wnd.location.search;
- var re = /debug[^\/]*$/;
- return re.test(parameters);
+ return true;
} else {
return false;
}
@@ -618,12 +624,11 @@ public class ApplicationConfiguration implements EntryPoint {
*
* @return <code>true</code> if debug logging should be quiet
*/
- public native static boolean isQuietDebugMode()
- /*-{
- var uri = $wnd.location;
- var re = /debug=q[^\/]*$/;
- return re.test(uri);
- }-*/;
+ public static boolean isQuietDebugMode() {
+ String debugParameter = Window.Location.getParameter("debug");
+ return isDebugAvailable() && debugParameter != null
+ && debugParameter.startsWith("q");
+ }
/**
* Checks whether information from the web browser (e.g. uri fragment and
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 93a51e6e96..f0470c8ee8 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -40,7 +40,7 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
-import com.vaadin.terminal.gwt.client.communication.HasJavascriptConnectorHelper;
+import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper;
import com.vaadin.terminal.gwt.client.communication.JsonDecoder;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
@@ -50,6 +50,7 @@ import com.vaadin.terminal.gwt.client.communication.SharedState;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.communication.Type;
import com.vaadin.terminal.gwt.client.communication.UidlValue;
+import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
import com.vaadin.terminal.gwt.client.ui.VContextMenu;
import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager;
@@ -370,6 +371,25 @@ public class ApplicationConnection {
}-*/;
/**
+ * If on Liferay and logged in, ask the client side session management
+ * JavaScript to extend the session duration.
+ *
+ * Otherwise, Liferay client side JavaScript will explicitly expire the
+ * session even though the server side considers the session to be active.
+ * See ticket #8305 for more information.
+ */
+ protected native void extendLiferaySession()
+ /*-{
+ if ($wnd.Liferay && $wnd.Liferay.Session) {
+ $wnd.Liferay.Session.extend();
+ // if the extend banner is visible, hide it
+ if ($wnd.Liferay.Session.banner) {
+ $wnd.Liferay.Session.banner.remove();
+ }
+ }
+ }-*/;
+
+ /**
* Get the active Console for writing debug messages. May return an actual
* logging console, or the NullConsole if debugging is not turned on.
*
@@ -851,6 +871,14 @@ public class ApplicationConnection {
public void execute() {
if (!hasActiveRequest()) {
hideLoadingIndicator();
+
+ // If on Liferay and session expiration management is in
+ // use, extend session duration on each request.
+ // Doing it here rather than before the request to improve
+ // responsiveness.
+ // Postponed until the end of the next request if other
+ // requests still pending.
+ extendLiferaySession();
}
}
});
@@ -1415,8 +1443,8 @@ public class ApplicationConnection {
JSONObject stateJson = new JSONObject(
states.getJavaScriptObject(connectorId));
- if (connector instanceof HasJavascriptConnectorHelper) {
- ((HasJavascriptConnectorHelper) connector)
+ if (connector instanceof HasJavaScriptConnectorHelper) {
+ ((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper()
.setNativeState(
stateJson.getJavaScriptObject());
@@ -1491,6 +1519,10 @@ public class ApplicationConnection {
if (childConnector instanceof ComponentConnector) {
newComponents
.add((ComponentConnector) childConnector);
+ } else if (!(childConnector instanceof AbstractExtensionConnector)) {
+ throw new IllegalStateException(
+ Util.getConnectorString(childConnector)
+ + " is not a ComponentConnector nor an AbstractExtensionConnector");
}
if (childConnector.getParent() != parentConnector) {
// Avoid extra calls to setParent
diff --git a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
index e12c002930..82cf925ec1 100644
--- a/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
+++ b/src/com/vaadin/terminal/gwt/client/BrowserInfo.java
@@ -31,6 +31,9 @@ public class BrowserInfo {
private static final String OS_ANDROID = "android";
private static final String OS_IOS = "ios";
+ // Common CSS class for all touch devices
+ private static final String UI_TOUCH = "touch";
+
private static BrowserInfo instance;
private static String cssClass = null;
@@ -169,7 +172,9 @@ public class BrowserInfo {
if (osClass != null) {
cssClass = cssClass + " " + prefix + osClass;
}
-
+ if (isTouchDevice()) {
+ cssClass = cssClass + " " + prefix + UI_TOUCH;
+ }
}
return cssClass;
@@ -344,15 +349,14 @@ public class BrowserInfo {
if (!isTouchDevice()) {
return false;
}
-
- if (isAndroid() && isWebkit() && getWebkitVersion() < 534) {
- return true;
+ if (isAndroid() && isWebkit() && getWebkitVersion() >= 534) {
+ return false;
}
- // if (isIOS() && isWebkit() && getWebkitVersion() < ???) {
- // return true;
+ // Cannot enable native touch scrolling on iOS 5 until #8792 is resolved
+ // if (isIOS() && isWebkit() && getWebkitVersion() >= 534) {
+ // return false;
// }
-
- return false;
+ return true;
}
/**
diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java b/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java
new file mode 100644
index 0000000000..bd62a759cb
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/JavaScriptConnectorHelper.java
@@ -0,0 +1,372 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.user.client.Element;
+import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
+
+public class JavaScriptConnectorHelper {
+
+ public interface JavaScriptConnectorState {
+ public Set<String> getCallbackNames();
+
+ public Map<String, Set<String>> getRpcInterfaces();
+ }
+
+ private final ServerConnector connector;
+ private final JavaScriptObject nativeState = JavaScriptObject
+ .createObject();
+ private final JavaScriptObject rpcMap = JavaScriptObject.createObject();
+
+ private final Map<String, JavaScriptObject> rpcObjects = new HashMap<String, JavaScriptObject>();
+ private final Map<String, Set<String>> rpcMethods = new HashMap<String, Set<String>>();
+
+ private JavaScriptObject connectorWrapper;
+ private int tag;
+
+ private boolean inited = false;
+
+ public JavaScriptConnectorHelper(ServerConnector connector) {
+ this.connector = connector;
+
+ // Wildcard rpc object
+ rpcObjects.put("", JavaScriptObject.createObject());
+ }
+
+ public void init() {
+ connector.addStateChangeHandler(new StateChangeHandler() {
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ JavaScriptObject wrapper = getConnectorWrapper();
+ JavaScriptConnectorState state = getConnectorState();
+
+ for (String callback : state.getCallbackNames()) {
+ ensureCallback(JavaScriptConnectorHelper.this, wrapper,
+ callback);
+ }
+
+ for (Entry<String, Set<String>> entry : state
+ .getRpcInterfaces().entrySet()) {
+ String rpcName = entry.getKey();
+ String jsName = getJsInterfaceName(rpcName);
+ if (!rpcObjects.containsKey(jsName)) {
+ Set<String> methods = entry.getValue();
+ rpcObjects.put(jsName,
+ createRpcObject(rpcName, methods));
+
+ // Init all methods for wildcard rpc
+ for (String method : methods) {
+ JavaScriptObject wildcardRpcObject = rpcObjects
+ .get("");
+ Set<String> interfaces = rpcMethods.get(method);
+ if (interfaces == null) {
+ interfaces = new HashSet<String>();
+ rpcMethods.put(method, interfaces);
+ attachRpcMethod(wildcardRpcObject, null, method);
+ }
+ interfaces.add(rpcName);
+ }
+ }
+ }
+
+ // Init after setting up callbacks & rpc
+ if (!inited) {
+ initJavaScript();
+ inited = true;
+ }
+
+ fireNativeStateChange(wrapper);
+ }
+ });
+ }
+
+ private static String getJsInterfaceName(String rpcName) {
+ return rpcName.replace('$', '.');
+ }
+
+ protected JavaScriptObject createRpcObject(String iface, Set<String> methods) {
+ JavaScriptObject object = JavaScriptObject.createObject();
+
+ for (String method : methods) {
+ attachRpcMethod(object, iface, method);
+ }
+
+ return object;
+ }
+
+ private boolean initJavaScript() {
+ ApplicationConfiguration conf = connector.getConnection()
+ .getConfiguration();
+ ArrayList<String> attemptedNames = new ArrayList<String>();
+ Integer tag = Integer.valueOf(this.tag);
+ while (tag != null) {
+ String serverSideClassName = conf.getServerSideClassNameForTag(tag);
+ String initFunctionName = serverSideClassName
+ .replaceAll("\\.", "_");
+ if (tryInitJs(initFunctionName, getConnectorWrapper())) {
+ VConsole.log("JavaScript connector initialized using "
+ + initFunctionName);
+ return true;
+ } else {
+ VConsole.log("No JavaScript function " + initFunctionName
+ + " found");
+ attemptedNames.add(initFunctionName);
+ tag = conf.getParentTag(tag.intValue());
+ }
+ }
+ VConsole.log("No JavaScript init for connector not found");
+ showInitProblem(attemptedNames);
+ return false;
+ }
+
+ protected void showInitProblem(ArrayList<String> attemptedNames) {
+ // Default does nothing
+ }
+
+ private static native boolean tryInitJs(String initFunctionName,
+ JavaScriptObject connectorWrapper)
+ /*-{
+ if (typeof $wnd[initFunctionName] == 'function') {
+ $wnd[initFunctionName].apply(connectorWrapper);
+ return true;
+ } else {
+ return false;
+ }
+ }-*/;
+
+ private JavaScriptObject getConnectorWrapper() {
+ if (connectorWrapper == null) {
+ connectorWrapper = createConnectorWrapper(this, nativeState,
+ rpcMap, connector.getConnectorId(), rpcObjects);
+ }
+
+ return connectorWrapper;
+ }
+
+ private static native void fireNativeStateChange(
+ JavaScriptObject connectorWrapper)
+ /*-{
+ if (typeof connectorWrapper.onStateChange == 'function') {
+ connectorWrapper.onStateChange();
+ }
+ }-*/;
+
+ private static native JavaScriptObject createConnectorWrapper(
+ JavaScriptConnectorHelper h, JavaScriptObject nativeState,
+ JavaScriptObject registeredRpc, String connectorId,
+ Map<String, JavaScriptObject> rpcObjects)
+ /*-{
+ return {
+ 'getConnectorId': function() {
+ return connectorId;
+ },
+ 'getParentId': $entry(function(connectorId) {
+ return h.@com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper::getParentId(Ljava/lang/String;)(connectorId);
+ }),
+ 'getState': function() {
+ return nativeState;
+ },
+ 'getRpcProxy': $entry(function(iface) {
+ if (!iface) {
+ iface = '';
+ }
+ return rpcObjects.@java.util.Map::get(Ljava/lang/Object;)(iface);
+ }),
+ 'getWidgetElement': $entry(function(connectorId) {
+ return h.@com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper::getWidgetElement(Ljava/lang/String;)(connectorId);
+ }),
+ 'registerRpc': function(iface, rpcHandler) {
+ //registerRpc(handler) -> registerRpc('', handler);
+ if (!rpcHandler) {
+ rpcHandler = iface;
+ iface = '';
+ }
+ if (!registeredRpc[iface]) {
+ registeredRpc[iface] = [];
+ }
+ registeredRpc[iface].push(rpcHandler);
+ },
+ };
+ }-*/;
+
+ private native void attachRpcMethod(JavaScriptObject rpc, String iface,
+ String method)
+ /*-{
+ var self = this;
+ rpc[method] = $entry(function() {
+ self.@com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper::fireRpc(Ljava/lang/String;Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(iface, method, arguments);
+ });
+ }-*/;
+
+ private String getParentId(String connectorId) {
+ ServerConnector target = getConnector(connectorId);
+ if (target == null) {
+ return null;
+ }
+ ServerConnector parent = target.getParent();
+ if (parent == null) {
+ return null;
+ } else {
+ return parent.getConnectorId();
+ }
+ }
+
+ private Element getWidgetElement(String connectorId) {
+ ServerConnector target = getConnector(connectorId);
+ if (target instanceof ComponentConnector) {
+ return ((ComponentConnector) target).getWidget().getElement();
+ } else {
+ return null;
+ }
+ }
+
+ private ServerConnector getConnector(String connectorId) {
+ if (connectorId == null || connectorId.length() == 0) {
+ return connector;
+ }
+
+ return ConnectorMap.get(connector.getConnection())
+ .getConnector(connectorId);
+ }
+
+ private void fireRpc(String iface, String method,
+ JsArray<JavaScriptObject> arguments) {
+ if (iface == null) {
+ iface = findWildcardInterface(method);
+ }
+
+ JSONArray argumentsArray = new JSONArray(arguments);
+ Object[] parameters = new Object[arguments.length()];
+ for (int i = 0; i < parameters.length; i++) {
+ parameters[i] = argumentsArray.get(i);
+ }
+ connector.getConnection().addMethodInvocationToQueue(
+ new MethodInvocation(connector.getConnectorId(), iface, method,
+ parameters), true);
+ }
+
+ private String findWildcardInterface(String method) {
+ Set<String> interfaces = rpcMethods.get(method);
+ if (interfaces.size() == 1) {
+ return interfaces.iterator().next();
+ } else {
+ // TODO Resolve conflicts using argument count and types
+ String interfaceList = "";
+ for (String iface : interfaces) {
+ if (interfaceList.length() != 0) {
+ interfaceList += ", ";
+ }
+ interfaceList += getJsInterfaceName(iface);
+ }
+
+ throw new IllegalStateException(
+ "Can not call method "
+ + method
+ + " for wildcard rpc proxy because the function is defined for multiple rpc interfaces: "
+ + interfaceList
+ + ". Retrieve a rpc proxy for a specific interface using getRpcProxy(interfaceName) to use the function.");
+ }
+ }
+
+ private void fireCallback(String name, JsArray<JavaScriptObject> arguments) {
+ MethodInvocation invocation = new MethodInvocation(
+ connector.getConnectorId(),
+ "com.vaadin.ui.JavaScript$JavaScriptCallbackRpc", "call",
+ new Object[] { name, new JSONArray(arguments) });
+ connector.getConnection().addMethodInvocationToQueue(invocation, true);
+ }
+
+ public void setNativeState(JavaScriptObject state) {
+ updateNativeState(nativeState, state);
+ }
+
+ private static native void updateNativeState(JavaScriptObject state,
+ JavaScriptObject input)
+ /*-{
+ // Copy all fields to existing state object
+ for(var key in state) {
+ if (state.hasOwnProperty(key)) {
+ delete state[key];
+ }
+ }
+
+ for(var key in input) {
+ if (input.hasOwnProperty(key)) {
+ state[key] = input[key];
+ }
+ }
+ }-*/;
+
+ public Object[] decodeRpcParameters(JSONArray parametersJson) {
+ return new Object[] { parametersJson.getJavaScriptObject() };
+ }
+
+ public void setTag(int tag) {
+ this.tag = tag;
+ }
+
+ public void invokeJsRpc(MethodInvocation invocation,
+ JSONArray parametersJson) {
+ String iface = invocation.getInterfaceName();
+ String method = invocation.getMethodName();
+ if ("com.vaadin.ui.JavaScript$JavaScriptCallbackRpc".equals(iface)
+ && "call".equals(method)) {
+ String callbackName = parametersJson.get(0).isString()
+ .stringValue();
+ JavaScriptObject arguments = parametersJson.get(1).isArray()
+ .getJavaScriptObject();
+ invokeCallback(getConnectorWrapper(), callbackName, arguments);
+ } else {
+ JavaScriptObject arguments = parametersJson.getJavaScriptObject();
+ invokeJsRpc(rpcMap, iface, method, arguments);
+ // Also invoke wildcard interface
+ invokeJsRpc(rpcMap, "", method, arguments);
+ }
+ }
+
+ private static native void invokeCallback(JavaScriptObject connector,
+ String name, JavaScriptObject arguments)
+ /*-{
+ connector[name].apply(connector, arguments);
+ }-*/;
+
+ private static native void invokeJsRpc(JavaScriptObject rpcMap,
+ String interfaceName, String methodName, JavaScriptObject parameters)
+ /*-{
+ var targets = rpcMap[interfaceName];
+ if (!targets) {
+ return;
+ }
+ for(var i = 0; i < targets.length; i++) {
+ var target = targets[i];
+ target[methodName].apply(target, parameters);
+ }
+ }-*/;
+
+ private static native void ensureCallback(JavaScriptConnectorHelper h,
+ JavaScriptObject connector, String name)
+ /*-{
+ connector[name] = $entry(function() {
+ var args = Array.prototype.slice.call(arguments, 0);
+ h.@com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper::fireCallback(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(name, args);
+ });
+ }-*/;
+
+ private JavaScriptConnectorState getConnectorState() {
+ return (JavaScriptConnectorState) connector.getState();
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java b/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java
new file mode 100644
index 0000000000..2a97e4a770
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java
@@ -0,0 +1,32 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import com.vaadin.terminal.AbstractJavaScriptExtension;
+import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper;
+import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
+import com.vaadin.terminal.gwt.client.ui.Connect;
+
+@Connect(AbstractJavaScriptExtension.class)
+public final class JavaScriptExtension extends AbstractExtensionConnector
+ implements HasJavaScriptConnectorHelper {
+ private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper(
+ this);
+
+ @Override
+ protected void init() {
+ super.init();
+ helper.init();
+ }
+
+ public JavaScriptConnectorHelper getJavascriptConnectorHelper() {
+ return helper;
+ }
+
+ @Override
+ public JavaScriptExtensionState getState() {
+ return (JavaScriptExtensionState) super.getState();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java b/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java
new file mode 100644
index 0000000000..e7bfbc4bb2
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/JavaScriptExtensionState.java
@@ -0,0 +1,36 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper.JavaScriptConnectorState;
+import com.vaadin.terminal.gwt.client.communication.SharedState;
+
+public class JavaScriptExtensionState extends SharedState implements
+ JavaScriptConnectorState {
+
+ private Set<String> callbackNames = new HashSet<String>();
+ private Map<String, Set<String>> rpcInterfaces = new HashMap<String, Set<String>>();
+
+ public Set<String> getCallbackNames() {
+ return callbackNames;
+ }
+
+ public void setCallbackNames(Set<String> callbackNames) {
+ this.callbackNames = callbackNames;
+ }
+
+ public Map<String, Set<String>> getRpcInterfaces() {
+ return rpcInterfaces;
+ }
+
+ public void setRpcInterfaces(Map<String, Set<String>> rpcInterfaces) {
+ this.rpcInterfaces = rpcInterfaces;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/JavascriptConnectorHelper.java b/src/com/vaadin/terminal/gwt/client/JavascriptConnectorHelper.java
deleted file mode 100644
index ab0e62222c..0000000000
--- a/src/com/vaadin/terminal/gwt/client/JavascriptConnectorHelper.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import java.util.ArrayList;
-
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.JsArray;
-import com.google.gwt.json.client.JSONArray;
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
-
-public class JavascriptConnectorHelper {
-
- private final ServerConnector connector;
- private final JavaScriptObject nativeState = JavaScriptObject
- .createObject();
- private final JavaScriptObject rpcMap = JavaScriptObject.createObject();
-
- private JavaScriptObject connectorWrapper;
- private int tag;
-
- public JavascriptConnectorHelper(ServerConnector connector) {
- this.connector = connector;
- }
-
- public boolean init() {
- ApplicationConfiguration conf = connector.getConnection()
- .getConfiguration();
- ArrayList<String> attemptedNames = new ArrayList<String>();
- Integer tag = Integer.valueOf(this.tag);
- while (tag != null) {
- String serverSideClassName = conf.getServerSideClassNameForTag(tag);
- String initFunctionName = serverSideClassName
- .replaceAll("\\.", "_");
- if (tryInitJs(initFunctionName, getConnectorWrapper())) {
- VConsole.log("Javascript connector initialized using "
- + initFunctionName);
- return true;
- } else {
- VConsole.log("No javascript function " + initFunctionName
- + " found");
- attemptedNames.add(initFunctionName);
- tag = conf.getParentTag(tag.intValue());
- }
- }
- VConsole.log("No javascript init for connector not found");
- showInitProblem(attemptedNames);
- return false;
- }
-
- protected void showInitProblem(ArrayList<String> attemptedNames) {
- // Default does nothing
- }
-
- private static native boolean tryInitJs(String initFunctionName,
- JavaScriptObject connectorWrapper)
- /*-{
- if (typeof $wnd[initFunctionName] == 'function') {
- $wnd[initFunctionName].apply(connectorWrapper);
- return true;
- } else {
- return false;
- }
- }-*/;
-
- private JavaScriptObject getConnectorWrapper() {
- if (connectorWrapper == null) {
- connectorWrapper = createConnectorWrapper();
- }
-
- return connectorWrapper;
- }
-
- protected JavaScriptObject createConnectorWrapper() {
- return createConnectorWrapper(this, nativeState, rpcMap,
- connector.getConnectorId());
- }
-
- public void fireNativeStateChange() {
- fireNativeStateChange(getConnectorWrapper());
- }
-
- private static native void fireNativeStateChange(
- JavaScriptObject connectorWrapper)
- /*-{
- if (typeof connectorWrapper.onStateChange == 'function') {
- connectorWrapper.onStateChange();
- }
- }-*/;
-
- private static native JavaScriptObject createConnectorWrapper(
- JavascriptConnectorHelper h, JavaScriptObject nativeState,
- JavaScriptObject registeredRpc, String connectorId)
- /*-{
- return {
- 'getConnectorId': function() {
- return connectorId;
- },
- 'getState': function() {
- return nativeState;
- },
- 'getRpcProxyFunction': function(iface, method) {
- return $entry(function() {
- h.@com.vaadin.terminal.gwt.client.JavascriptConnectorHelper::fireRpc(Ljava/lang/String;Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(iface, method, arguments);
- });
- },
- 'getCallback': function(name) {
- return $entry(function() {
- var args = [name, Array.prototype.slice.call(arguments, 0)];
- var iface = "com.vaadin.ui.JavascriptManager$JavascriptCallbackRpc";
- var method = "call";
- h.@com.vaadin.terminal.gwt.client.JavascriptConnectorHelper::fireRpc(Ljava/lang/String;Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(iface, method, args);
- });
- },
- 'registerCallback': function(name, callback) {
- //TODO maintain separate map
- if (!registeredRpc[name]) {
- registeredRpc[name] = [];
- }
- registeredRpc[name].push(callback);
- },
- 'registerRpc': function(iface, rpcHandler) {
- if (!registeredRpc[iface]) {
- registeredRpc[iface] = [];
- }
- registeredRpc[iface].push(rpcHandler);
- },
- };
- }-*/;
-
- private void fireRpc(String iface, String method,
- JsArray<JavaScriptObject> arguments) {
- JSONArray argumentsArray = new JSONArray(arguments);
- Object[] parameters = new Object[arguments.length()];
- for (int i = 0; i < parameters.length; i++) {
- parameters[i] = argumentsArray.get(i);
- }
- connector.getConnection().addMethodInvocationToQueue(
- new MethodInvocation(connector.getConnectorId(), iface, method,
- parameters), true);
- }
-
- public void setNativeState(JavaScriptObject state) {
- updateNativeState(nativeState, state);
- }
-
- private static native void updateNativeState(JavaScriptObject state,
- JavaScriptObject input)
- /*-{
- // Copy all fields to existing state object
- for(var key in state) {
- if (state.hasOwnProperty(key)) {
- delete state[key];
- }
- }
-
- for(var key in input) {
- if (input.hasOwnProperty(key)) {
- state[key] = input[key];
- }
- }
- }-*/;
-
- public Object[] decodeRpcParameters(JSONArray parametersJson) {
- return new Object[] { parametersJson.getJavaScriptObject() };
- }
-
- public void setTag(int tag) {
- this.tag = tag;
- }
-
- public void invokeJsRpc(MethodInvocation invocation,
- JSONArray parametersJson) {
- if ("com.vaadin.ui.JavascriptManager$JavascriptCallbackRpc"
- .equals(invocation.getInterfaceName())
- && "call".equals(invocation.getMethodName())) {
- invokeJsRpc(rpcMap, parametersJson.get(0).isString().stringValue(),
- null, parametersJson.get(1).isArray().getJavaScriptObject());
- } else {
- invokeJsRpc(rpcMap, invocation.getInterfaceName(),
- invocation.getMethodName(),
- parametersJson.getJavaScriptObject());
- }
- }
-
- private static native void invokeJsRpc(JavaScriptObject rpcMap,
- String interfaceName, String methodName, JavaScriptObject parameters)
- /*-{
- var targets = rpcMap[interfaceName];
- if (!targets) {
- return;
- }
- for(var i = 0; i < targets.length; i++) {
- var target = targets[i];
- if (methodName === null && typeof target === 'function') {
- target.apply($wnd, parameters);
- } else {
- target[methodName].apply(target, parameters);
- }
- }
- }-*/;
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/JavascriptExtension.java b/src/com/vaadin/terminal/gwt/client/JavascriptExtension.java
deleted file mode 100644
index 6c098a52f6..0000000000
--- a/src/com/vaadin/terminal/gwt/client/JavascriptExtension.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import com.vaadin.terminal.AbstractJavascriptExtension;
-import com.vaadin.terminal.gwt.client.communication.HasJavascriptConnectorHelper;
-import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
-import com.vaadin.terminal.gwt.client.ui.AbstractConnector;
-import com.vaadin.terminal.gwt.client.ui.Connect;
-
-@Connect(AbstractJavascriptExtension.class)
-public class JavascriptExtension extends AbstractConnector implements
- HasJavascriptConnectorHelper {
- private final JavascriptConnectorHelper helper = new JavascriptConnectorHelper(
- this);
-
- @Override
- protected void init() {
- helper.init();
- }
-
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- super.onStateChanged(stateChangeEvent);
- helper.fireNativeStateChange();
- }
-
- public JavascriptConnectorHelper getJavascriptConnectorHelper() {
- return helper;
- }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/Util.java b/src/com/vaadin/terminal/gwt/client/Util.java
index 87bf27fc27..d3cb54160d 100644
--- a/src/com/vaadin/terminal/gwt/client/Util.java
+++ b/src/com/vaadin/terminal/gwt/client/Util.java
@@ -911,6 +911,22 @@ public class Util {
}
/**
+ * Find the element corresponding to the coordinates in the passed mouse
+ * event. Please note that this is not always the same as the target of the
+ * event e.g. if event capture is used.
+ *
+ * @param event
+ * the mouse event to get coordinates from
+ * @return the element at the coordinates of the event
+ */
+ public static Element getElementUnderMouse(NativeEvent event) {
+ int pageX = getTouchOrMouseClientX(event);
+ int pageY = getTouchOrMouseClientY(event);
+
+ return getElementFromPoint(pageX, pageY);
+ }
+
+ /**
* A helper method to return the client position from an event. Returns
* position from either first changed touch (if touch event) or from the
* event itself.
diff --git a/src/com/vaadin/terminal/gwt/client/WidgetSet.java b/src/com/vaadin/terminal/gwt/client/WidgetSet.java
index ecbfb0ecc9..3d7e838c62 100644
--- a/src/com/vaadin/terminal/gwt/client/WidgetSet.java
+++ b/src/com/vaadin/terminal/gwt/client/WidgetSet.java
@@ -5,7 +5,7 @@
package com.vaadin.terminal.gwt.client;
import com.google.gwt.core.client.GWT;
-import com.vaadin.terminal.gwt.client.communication.HasJavascriptConnectorHelper;
+import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper;
import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;
public class WidgetSet {
@@ -54,8 +54,8 @@ public class WidgetSet {
* let the auto generated code instantiate this type
*/
ServerConnector connector = widgetMap.instantiate(classType);
- if (connector instanceof HasJavascriptConnectorHelper) {
- ((HasJavascriptConnectorHelper) connector)
+ if (connector instanceof HasJavaScriptConnectorHelper) {
+ ((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper().setTag(tag);
}
return connector;
diff --git a/src/com/vaadin/terminal/gwt/client/communication/HasJavaScriptConnectorHelper.java b/src/com/vaadin/terminal/gwt/client/communication/HasJavaScriptConnectorHelper.java
new file mode 100644
index 0000000000..a5191a5fed
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/communication/HasJavaScriptConnectorHelper.java
@@ -0,0 +1,11 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.communication;
+
+import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper;
+
+public interface HasJavaScriptConnectorHelper {
+ public JavaScriptConnectorHelper getJavascriptConnectorHelper();
+}
diff --git a/src/com/vaadin/terminal/gwt/client/communication/HasJavascriptConnectorHelper.java b/src/com/vaadin/terminal/gwt/client/communication/HasJavascriptConnectorHelper.java
deleted file mode 100644
index 74bc75da66..0000000000
--- a/src/com/vaadin/terminal/gwt/client/communication/HasJavascriptConnectorHelper.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.communication;
-
-import com.vaadin.terminal.gwt.client.JavascriptConnectorHelper;
-
-public interface HasJavascriptConnectorHelper {
- public JavascriptConnectorHelper getJavascriptConnectorHelper();
-}
diff --git a/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java b/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
index e0ffb40125..07d6292ce2 100644
--- a/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
+++ b/src/com/vaadin/terminal/gwt/client/communication/RpcManager.java
@@ -89,8 +89,8 @@ public class RpcManager {
MethodInvocation invocation = new MethodInvocation(connectorId,
interfaceName, methodName);
- if (connector instanceof HasJavascriptConnectorHelper) {
- ((HasJavascriptConnectorHelper) connector)
+ if (connector instanceof HasJavaScriptConnectorHelper) {
+ ((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper().invokeJsRpc(invocation,
parametersJson);
} else {
diff --git a/src/com/vaadin/terminal/gwt/client/extensions/AbstractExtensionConnector.java b/src/com/vaadin/terminal/gwt/client/extensions/AbstractExtensionConnector.java
new file mode 100644
index 0000000000..bcefcf05cb
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/extensions/AbstractExtensionConnector.java
@@ -0,0 +1,27 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.extensions;
+
+import com.vaadin.terminal.gwt.client.ServerConnector;
+import com.vaadin.terminal.gwt.client.ui.AbstractConnector;
+
+public abstract class AbstractExtensionConnector extends AbstractConnector {
+ @Override
+ public void setParent(ServerConnector parent) {
+ ServerConnector oldParent = getParent();
+ if (oldParent != null && oldParent != parent) {
+ throw new IllegalStateException(
+ "An extension can not be moved from one parent to another.");
+ }
+
+ super.setParent(parent);
+
+ extend(parent);
+ }
+
+ protected void extend(ServerConnector target) {
+ // Default does nothing
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/ExecuteJavaScriptRpc.java b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/ExecuteJavaScriptRpc.java
new file mode 100644
index 0000000000..f1185586d5
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/ExecuteJavaScriptRpc.java
@@ -0,0 +1,11 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.extensions.javascriptmanager;
+
+import com.vaadin.terminal.gwt.client.communication.ClientRpc;
+
+public interface ExecuteJavaScriptRpc extends ClientRpc {
+ public void executeJavaScript(String script);
+}
diff --git a/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
new file mode 100644
index 0000000000..8656783a86
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
@@ -0,0 +1,119 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.extensions.javascriptmanager;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.json.client.JSONArray;
+import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
+import com.vaadin.terminal.gwt.client.ui.Connect;
+import com.vaadin.ui.JavaScript;
+
+@Connect(JavaScript.class)
+public class JavaScriptManagerConnector extends AbstractExtensionConnector {
+ private Set<String> currentNames = new HashSet<String>();
+
+ @Override
+ protected void init() {
+ registerRpc(ExecuteJavaScriptRpc.class, new ExecuteJavaScriptRpc() {
+ public void executeJavaScript(String Script) {
+ eval(Script);
+ }
+ });
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ Set<String> newNames = getState().getNames();
+
+ // Current names now only contains orphan callbacks
+ currentNames.removeAll(newNames);
+
+ for (String name : currentNames) {
+ removeCallback(name);
+ }
+
+ currentNames = new HashSet<String>(newNames);
+ for (String name : newNames) {
+ addCallback(name);
+ }
+ }
+
+ // TODO Ensure we don't overwrite anything (important) in $wnd
+ private native void addCallback(String name)
+ /*-{
+ var m = this;
+ var target = $wnd;
+ var parts = name.split('.');
+
+ for(var i = 0; i < parts.length - 1; i++) {
+ var part = parts[i];
+ if (target[part] === undefined) {
+ target[part] = {};
+ }
+ target = target[part];
+ }
+
+ target[parts[parts.length - 1]] = $entry(function() {
+ //Must make a copy because arguments is an array-like object (not instanceof Array), causing suboptimal JSON encoding
+ var args = Array.prototype.slice.call(arguments, 0);
+ m.@com.vaadin.terminal.gwt.client.extensions.javascriptmanager.JavaScriptManagerConnector::sendRpc(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(name, args);
+ });
+ }-*/;
+
+ // TODO only remove what we actually added
+ // TODO We might leave empty objects behind, but there's no good way of
+ // knowing whether they are unused
+ private native void removeCallback(String name)
+ /*-{
+ var target = $wnd;
+ var parts = name.split('.');
+
+ for(var i = 0; i < parts.length - 1; i++) {
+ var part = parts[i];
+ if (target[part] === undefined) {
+ $wnd.console.log(part,'not defined in',target);
+ // No longer attached -> nothing more to do
+ return;
+ }
+ target = target[part];
+ }
+
+ $wnd.console.log('removing',parts[parts.length - 1],'from',target);
+ delete target[parts[parts.length - 1]];
+ }-*/;
+
+ private static native void eval(String script)
+ /*-{
+ if(script) {
+ (new $wnd.Function(script)).apply($wnd);
+ }
+ }-*/;
+
+ public void sendRpc(String name, JsArray<JavaScriptObject> arguments) {
+ Object[] parameters = new Object[] { name, new JSONArray(arguments) };
+
+ /*
+ * Must invoke manually as the RPC interface can't be used in GWT
+ * because of the JSONArray parameter
+ */
+ getConnection().addMethodInvocationToQueue(
+ new MethodInvocation(getConnectorId(),
+ "com.vaadin.ui.JavaScript$JavaScriptCallbackRpc",
+ "call", parameters), true);
+ }
+
+ @Override
+ public JavaScriptManagerState getState() {
+ return (JavaScriptManagerState) super.getState();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerState.java b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerState.java
index 77794ffdca..fc246aff04 100644
--- a/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerState.java
+++ b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavaScriptManagerState.java
@@ -9,7 +9,7 @@ import java.util.Set;
import com.vaadin.terminal.gwt.client.communication.SharedState;
-public class JavascriptManagerState extends SharedState {
+public class JavaScriptManagerState extends SharedState {
private Set<String> names = new HashSet<String>();
public Set<String> getNames() {
diff --git a/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerConnector.java b/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerConnector.java
deleted file mode 100644
index 979a6d22c4..0000000000
--- a/src/com/vaadin/terminal/gwt/client/extensions/javascriptmanager/JavascriptManagerConnector.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.extensions.javascriptmanager;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.JsArray;
-import com.google.gwt.json.client.JSONArray;
-import com.vaadin.terminal.gwt.client.communication.MethodInvocation;
-import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
-import com.vaadin.terminal.gwt.client.ui.AbstractConnector;
-import com.vaadin.terminal.gwt.client.ui.Connect;
-import com.vaadin.ui.JavascriptManager;
-
-@Connect(JavascriptManager.class)
-public class JavascriptManagerConnector extends AbstractConnector {
- private Set<String> currentNames = new HashSet<String>();
-
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- super.onStateChanged(stateChangeEvent);
-
- Set<String> newNames = getState().getNames();
-
- // Current names now only contains orphan callbacks
- currentNames.removeAll(newNames);
-
- for (String name : currentNames) {
- removeCallback(name);
- }
-
- currentNames = new HashSet<String>(newNames);
- for (String name : newNames) {
- addCallback(name);
- }
- }
-
- // TODO Ensure we don't overwrite anything (important) in $wnd
- private native void addCallback(String name)
- /*-{
- var m = this;
- $wnd[name] = $entry(function() {
- //Must make a copy because arguments is an array-like object (not instanceof Array), causing suboptimal JSON encoding
- var args = Array.prototype.slice.call(arguments, 0);
- m.@com.vaadin.terminal.gwt.client.extensions.javascriptmanager.JavascriptManagerConnector::sendRpc(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;)(name, args);
- });
- }-*/;
-
- // TODO only remove what we actually added
- private native void removeCallback(String name)
- /*-{
- delete $wnd[name];
- }-*/;
-
- public void sendRpc(String name, JsArray<JavaScriptObject> arguments) {
- Object[] parameters = new Object[] { name, new JSONArray(arguments) };
-
- /*
- * Must invoke manually as the RPC interface can't be used in GWT
- * because of the JSONArray parameter
- */
- getConnection()
- .addMethodInvocationToQueue(
- new MethodInvocation(
- getConnectorId(),
- "com.vaadin.ui.JavascriptManager$JavascriptCallbackRpc",
- "call", parameters), true);
- }
-
- @Override
- public JavascriptManagerState getState() {
- return (JavascriptManagerState) super.getState();
- }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java
index 31204aa0c6..e0ca798682 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractClickEventHandler.java
@@ -3,29 +3,76 @@
*/
package com.vaadin.terminal.gwt.client.ui;
+import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
import com.vaadin.terminal.gwt.client.ComponentConnector;
+import com.vaadin.terminal.gwt.client.Util;
-public abstract class AbstractClickEventHandler implements DoubleClickHandler,
- ContextMenuHandler, MouseUpHandler {
+public abstract class AbstractClickEventHandler implements MouseDownHandler,
+ MouseUpHandler, DoubleClickHandler, ContextMenuHandler {
- private HandlerRegistration doubleClickHandlerRegistration;
+ private HandlerRegistration mouseDownHandlerRegistration;
private HandlerRegistration mouseUpHandlerRegistration;
+ private HandlerRegistration doubleClickHandlerRegistration;
private HandlerRegistration contextMenuHandlerRegistration;
protected ComponentConnector connector;
private String clickEventIdentifier;
+ /**
+ * The element where the last mouse down event was registered.
+ */
+ private JavaScriptObject lastMouseDownTarget;
+
+ /**
+ * Set to true by {@link #mouseUpPreviewHandler} if it gets a mouseup at the
+ * same element as {@link #lastMouseDownTarget}.
+ */
+ private boolean mouseUpPreviewMatched = false;
+
+ private HandlerRegistration mouseUpEventPreviewRegistration;
+
+ /**
+ * Previews events after a mousedown to detect where the following mouseup
+ * hits.
+ */
+ private final NativePreviewHandler mouseUpPreviewHandler = new NativePreviewHandler() {
+
+ public void onPreviewNativeEvent(NativePreviewEvent event) {
+ if (event.getTypeInt() == Event.ONMOUSEUP) {
+ mouseUpEventPreviewRegistration.removeHandler();
+
+ // Event's reported target not always correct if event
+ // capture is in use
+ Element elementUnderMouse = Util.getElementUnderMouse(event
+ .getNativeEvent());
+ if (lastMouseDownTarget != null
+ && elementUnderMouse.cast() == lastMouseDownTarget) {
+ mouseUpPreviewMatched = true;
+ } else {
+ System.out.println("Ignoring mouseup from "
+ + elementUnderMouse + " when mousedown was on "
+ + lastMouseDownTarget);
+ }
+ }
+ }
+ };
+
public AbstractClickEventHandler(ComponentConnector connector,
String clickEventIdentifier) {
this.connector = connector;
@@ -36,25 +83,28 @@ public abstract class AbstractClickEventHandler implements DoubleClickHandler,
// Handle registering/unregistering of click handler depending on if
// server side listeners have been added or removed.
if (hasEventListener()) {
- if (mouseUpHandlerRegistration == null) {
+ if (mouseDownHandlerRegistration == null) {
+ mouseDownHandlerRegistration = registerHandler(this,
+ MouseDownEvent.getType());
mouseUpHandlerRegistration = registerHandler(this,
MouseUpEvent.getType());
- contextMenuHandlerRegistration = registerHandler(this,
- ContextMenuEvent.getType());
doubleClickHandlerRegistration = registerHandler(this,
DoubleClickEvent.getType());
+ contextMenuHandlerRegistration = registerHandler(this,
+ ContextMenuEvent.getType());
}
} else {
- if (mouseUpHandlerRegistration != null) {
+ if (mouseDownHandlerRegistration != null) {
// Remove existing handlers
- doubleClickHandlerRegistration.removeHandler();
+ mouseDownHandlerRegistration.removeHandler();
mouseUpHandlerRegistration.removeHandler();
+ doubleClickHandlerRegistration.removeHandler();
contextMenuHandlerRegistration.removeHandler();
- contextMenuHandlerRegistration = null;
+ mouseDownHandlerRegistration = null;
mouseUpHandlerRegistration = null;
doubleClickHandlerRegistration = null;
-
+ contextMenuHandlerRegistration = null;
}
}
@@ -93,6 +143,7 @@ public abstract class AbstractClickEventHandler implements DoubleClickHandler,
* Event handler for context menu. Prevents the browser context menu from
* popping up if there is a listener for right clicks.
*/
+
public void onContextMenu(ContextMenuEvent event) {
if (hasEventListener() && shouldFireEvent(event)) {
// Prevent showing the browser's context menu when there is a right
@@ -101,18 +152,34 @@ public abstract class AbstractClickEventHandler implements DoubleClickHandler,
}
}
- /**
- * Event handler for mouse up. This is used to detect all single click
- * events.
- */
+ public void onMouseDown(MouseDownEvent event) {
+ /*
+ * When getting a mousedown event, we must detect where the
+ * corresponding mouseup event if it's on a different part of the page.
+ */
+ lastMouseDownTarget = event.getNativeEvent().getEventTarget();
+ mouseUpPreviewMatched = false;
+ mouseUpEventPreviewRegistration = Event
+ .addNativePreviewHandler(mouseUpPreviewHandler);
+ }
+
public void onMouseUp(MouseUpEvent event) {
- // TODO For perfect accuracy we should check that a mousedown has
- // occured on this element before this mouseup and that no mouseup
- // has occured anywhere after that.
- if (hasEventListener() && shouldFireEvent(event)) {
+ /*
+ * Only fire a click if the mouseup hits the same element as the
+ * corresponding mousedown. This is first checked in the event preview
+ * but we can't fire the even there as the event might get canceled
+ * before it gets here.
+ */
+ if (hasEventListener()
+ && mouseUpPreviewMatched
+ && lastMouseDownTarget != null
+ && Util.getElementUnderMouse(event.getNativeEvent()) == lastMouseDownTarget
+ && shouldFireEvent(event)) {
// "Click" with left, right or middle button
fireClick(event.getNativeEvent());
}
+ mouseUpPreviewMatched = false;
+ lastMouseDownTarget = null;
}
/**
@@ -140,6 +207,7 @@ public abstract class AbstractClickEventHandler implements DoubleClickHandler,
* that browsers typically fail to prevent the second click event so a
* double click will result in two click events and one double click event.
*/
+
public void onDoubleClick(DoubleClickEvent event) {
if (hasEventListener() && shouldFireEvent(event)) {
fireClick(event.getNativeEvent());
diff --git a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
index 67dbd2d9d9..f0b9d518ca 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/AbstractComponentConnector.java
@@ -131,7 +131,22 @@ public abstract class AbstractComponentConnector extends AbstractConnector
public void setWidgetEnabled(boolean widgetEnabled) {
if (getWidget() instanceof HasEnabled) {
+ // set widget specific enabled state
((HasEnabled) getWidget()).setEnabled(widgetEnabled);
+ // add or remove v-disabled style name from the widget
+ getWidget().setStyleName(ApplicationConnection.DISABLED_CLASSNAME,
+ !widgetEnabled);
+ // make sure the caption has or has not v-disabled style
+ if (delegateCaptionHandling()) {
+ ServerConnector parent = getParent();
+ if (parent instanceof ComponentContainerConnector) {
+ ((ComponentContainerConnector) parent).updateCaption(this);
+ } else if (parent == null && !(this instanceof RootConnector)) {
+ VConsole.error("Parent of connector "
+ + Util.getConnectorString(this)
+ + " is null. This is typically an indication of a broken component hierarchy");
+ }
+ }
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
index cffdb1e68a..758f798ef2 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java
@@ -28,6 +28,7 @@ public abstract class ClickEventHandler extends AbstractClickEventHandler {
* @param event
* The native event that caused this click event
*/
+ @Override
protected void fireClick(NativeEvent event) {
MouseEventDetails mouseDetails = MouseEventDetailsBuilder
.buildMouseEventDetails(event, getRelativeToElement());
diff --git a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
index 62697c4d98..ef1ea8521b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/FocusableScrollPanel.java
@@ -34,8 +34,8 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
public FocusableScrollPanel() {
// Prevent IE standard mode bug when a AbsolutePanel is contained.
+ TouchScrollDelegate.enableTouchScrolling(this, getElement());
Style style = getElement().getStyle();
- style.setOverflow(Overflow.AUTO);
style.setProperty("zoom", "1");
style.setPosition(Position.RELATIVE);
}
@@ -153,7 +153,8 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements
* the new vertical scroll position, in pixels
*/
public void setScrollPosition(int position) {
- if (BrowserInfo.get().isAndroidWithBrokenScrollTop()) {
+ if (BrowserInfo.get().isAndroidWithBrokenScrollTop()
+ && BrowserInfo.get().requiresTouchScrollDelegate()) {
ArrayList<com.google.gwt.dom.client.Element> elements = TouchScrollDelegate
.getElements(getElement());
for (com.google.gwt.dom.client.Element el : elements) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java
new file mode 100644
index 0000000000..bb062a6677
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java
@@ -0,0 +1,42 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper;
+import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper;
+import com.vaadin.ui.AbstractJavaScriptComponent;
+
+@Connect(AbstractJavaScriptComponent.class)
+public final class JavaScriptComponentConnector extends
+ AbstractComponentConnector implements HasJavaScriptConnectorHelper {
+
+ private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper(
+ this) {
+ @Override
+ protected void showInitProblem(
+ java.util.ArrayList<String> attemptedNames) {
+ getWidget().showNoInitFound(attemptedNames);
+ }
+ };
+
+ @Override
+ public JavaScriptWidget getWidget() {
+ return (JavaScriptWidget) super.getWidget();
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+ helper.init();
+ }
+
+ public JavaScriptConnectorHelper getJavascriptConnectorHelper() {
+ return helper;
+ }
+
+ @Override
+ public JavaScriptComponentState getState() {
+ return (JavaScriptComponentState) super.getState();
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java
new file mode 100644
index 0000000000..6728f85ec9
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentState.java
@@ -0,0 +1,37 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.vaadin.terminal.gwt.client.ComponentState;
+import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper.JavaScriptConnectorState;
+
+public class JavaScriptComponentState extends ComponentState implements
+ JavaScriptConnectorState {
+
+ private Set<String> callbackNames = new HashSet<String>();
+ private Map<String, Set<String>> rpcInterfaces = new HashMap<String, Set<String>>();
+
+ public Set<String> getCallbackNames() {
+ return callbackNames;
+ }
+
+ public void setCallbackNames(Set<String> callbackNames) {
+ this.callbackNames = callbackNames;
+ }
+
+ public Map<String, Set<String>> getRpcInterfaces() {
+ return rpcInterfaces;
+ }
+
+ public void setRpcInterfaces(Map<String, Set<String>> rpcInterfaces) {
+ this.rpcInterfaces = rpcInterfaces;
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavascriptWidget.java b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptWidget.java
index 93a4417b1c..e6c3323893 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/JavascriptWidget.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptWidget.java
@@ -8,13 +8,13 @@ import java.util.ArrayList;
import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.ui.Widget;
-public class JavascriptWidget extends Widget {
- public JavascriptWidget() {
+public class JavaScriptWidget extends Widget {
+ public JavaScriptWidget() {
setElement(Document.get().createDivElement());
}
public void showNoInitFound(ArrayList<String> attemptedNames) {
- String message = "Could not initialize JavascriptConnector because no javascript init function was found. Make sure one of these functions are defined: <ul>";
+ String message = "Could not initialize JavaScriptConnector because no JavaScript init function was found. Make sure one of these functions are defined: <ul>";
for (String name : attemptedNames) {
message += "<li>" + name + "</li>";
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavascriptComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/JavascriptComponentConnector.java
deleted file mode 100644
index 57e65e91c6..0000000000
--- a/src/com/vaadin/terminal/gwt/client/ui/JavascriptComponentConnector.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-@VaadinApache2LicenseForJavaFiles@
- */
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.user.client.Element;
-import com.vaadin.terminal.gwt.client.JavascriptConnectorHelper;
-import com.vaadin.terminal.gwt.client.communication.HasJavascriptConnectorHelper;
-import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
-import com.vaadin.ui.AbstractJavascriptComponent;
-
-@Connect(AbstractJavascriptComponent.class)
-public class JavascriptComponentConnector extends AbstractComponentConnector
- implements HasJavascriptConnectorHelper {
-
- private final JavascriptConnectorHelper helper = new JavascriptConnectorHelper(
- this) {
- @Override
- protected void showInitProblem(
- java.util.ArrayList<String> attemptedNames) {
- getWidget().showNoInitFound(attemptedNames);
- }
-
- @Override
- protected JavaScriptObject createConnectorWrapper() {
- JavaScriptObject connectorWrapper = super.createConnectorWrapper();
- addGetWidgetElement(connectorWrapper, getWidget().getElement());
- return connectorWrapper;
- }
- };
-
- @Override
- protected void init() {
- helper.init();
- }
-
- @Override
- public void onStateChanged(StateChangeEvent stateChangeEvent) {
- super.onStateChanged(stateChangeEvent);
- helper.fireNativeStateChange();
- }
-
- private static native void addGetWidgetElement(
- JavaScriptObject connectorWrapper, Element element)
- /*-{
- connectorWrapper.getWidgetElement = function() {
- return element;
- };
- }-*/;
-
- @Override
- public JavascriptWidget getWidget() {
- return (JavascriptWidget) super.getWidget();
- }
-
- public JavascriptConnectorHelper getJavascriptConnectorHelper() {
- return helper;
- }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java b/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java
index 8b2248aff6..7302f9f2ac 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/TouchScrollDelegate.java
@@ -4,6 +4,8 @@
package com.vaadin.terminal.gwt.client.ui;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import com.google.gwt.animation.client.Animation;
import com.google.gwt.core.client.Duration;
@@ -15,10 +17,12 @@ import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.dom.client.TouchStartEvent;
+import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Event.NativePreviewHandler;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.VConsole;
@@ -68,7 +72,7 @@ public class TouchScrollDelegate implements NativePreviewHandler {
private static final double DECELERATION = 0.002;
private static final int MAX_DURATION = 1500;
private int origY;
- private Element[] scrollableElements;
+ private HashSet<Element> scrollableElements;
private Element scrolledElement;
private int origScrollTop;
private HandlerRegistration handlerRegistration;
@@ -86,8 +90,107 @@ public class TouchScrollDelegate implements NativePreviewHandler {
private static final boolean androidWithBrokenScrollTop = BrowserInfo.get()
.isAndroidWithBrokenScrollTop();
+ /**
+ * A helper class for making a widget scrollable. Uses native scrolling if
+ * supported by the browser, otherwise registers a touch start handler
+ * delegating to a TouchScrollDelegate instance.
+ */
+ public static class TouchScrollHandler implements TouchStartHandler {
+
+ private static final String SCROLLABLE_CLASSNAME = "v-scrollable";
+
+ private final TouchScrollDelegate delegate;
+ private final boolean requiresDelegate = BrowserInfo.get()
+ .requiresTouchScrollDelegate();
+
+ /**
+ * Constructs a scroll handler for the given widget.
+ *
+ * @param widget
+ * The widget that contains scrollable elements
+ * @param scrollables
+ * The elements of the widget that should be scrollable.
+ */
+ public TouchScrollHandler(Widget widget, Element... scrollables) {
+ if (requiresDelegate) {
+ delegate = new TouchScrollDelegate();
+ widget.addDomHandler(this, TouchStartEvent.getType());
+ } else {
+ delegate = null;
+ }
+ setElements(scrollables);
+ }
+
+ public void onTouchStart(TouchStartEvent event) {
+ assert delegate != null;
+ delegate.onTouchStart(event);
+ }
+
+ public void debug(Element e) {
+ VConsole.log("Classes: " + e.getClassName() + " overflow: "
+ + e.getStyle().getProperty("overflow") + " w-o-s: "
+ + e.getStyle().getProperty("WebkitOverflowScrolling"));
+ }
+
+ /**
+ * Registers the given element as scrollable.
+ */
+ public void addElement(Element scrollable) {
+ scrollable.addClassName(SCROLLABLE_CLASSNAME);
+ if (requiresDelegate) {
+ delegate.scrollableElements.add(scrollable);
+ }
+ }
+
+ /**
+ * Unregisters the given element as scrollable. Should be called when a
+ * previously-registered element is removed from the DOM to prevent
+ * memory leaks.
+ */
+ public void removeElement(Element scrollable) {
+ scrollable.removeClassName(SCROLLABLE_CLASSNAME);
+ if (requiresDelegate) {
+ delegate.scrollableElements.remove(scrollable);
+ }
+ }
+
+ /**
+ * Registers the given elements as scrollable, removing previously
+ * registered scrollables from this handler.
+ *
+ * @param scrollables
+ * The elements that should be scrollable
+ */
+ public void setElements(Element... scrollables) {
+ if (requiresDelegate) {
+ for (Element e : delegate.scrollableElements) {
+ e.removeClassName(SCROLLABLE_CLASSNAME);
+ }
+ delegate.scrollableElements.clear();
+ }
+ for (Element e : scrollables) {
+ addElement(e);
+ }
+ }
+ }
+
+ /**
+ * Makes the given elements scrollable, either natively or by using a
+ * TouchScrollDelegate, depending on platform capabilities.
+ *
+ * @param widget
+ * The widget that contains scrollable elements
+ * @param scrollables
+ * The elements inside the widget that should be scrollable
+ * @return A scroll handler for the given widget.
+ */
+ public static TouchScrollHandler enableTouchScrolling(Widget widget,
+ Element... scrollables) {
+ return new TouchScrollHandler(widget, scrollables);
+ }
+
public TouchScrollDelegate(Element... elements) {
- scrollableElements = elements;
+ setElements(elements);
}
public void setScrollHandler(ScrollHandler scrollHandler) {
@@ -535,8 +638,8 @@ public class TouchScrollDelegate implements NativePreviewHandler {
}
}
- public void setElements(com.google.gwt.user.client.Element[] elements) {
- scrollableElements = elements;
+ public void setElements(Element[] elements) {
+ scrollableElements = new HashSet<Element>(Arrays.asList(elements));
}
/**
diff --git a/src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java b/src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java
index dcd520bbb3..b83d5afb00 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/accordion/VAccordion.java
@@ -20,6 +20,8 @@ import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.terminal.gwt.client.ui.tabsheet.TabsheetBaseConnector;
import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheetBase;
@@ -35,8 +37,11 @@ public class VAccordion extends VTabsheetBase {
int selectedUIDLItemIndex = -1;
+ private final TouchScrollHandler touchScrollHandler;
+
public VAccordion() {
super(CLASSNAME);
+ touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
}
@Override
@@ -145,7 +150,6 @@ public class VAccordion extends VTabsheetBase {
}
}
}
-
if (!alreadyOpen) {
item.open();
activeTabIndex = itemIndex;
@@ -342,11 +346,13 @@ public class VAccordion extends VTabsheetBase {
DOM.appendChild(captionNode, caption.getElement());
DOM.appendChild(getElement(), captionNode);
DOM.appendChild(getElement(), content);
- setStyleName(CLASSNAME + "-item");
- DOM.setElementProperty(content, "className", CLASSNAME
- + "-item-content");
- DOM.setElementProperty(captionNode, "className", CLASSNAME
- + "-item-caption");
+
+ getElement().addClassName(CLASSNAME + "-item");
+ captionNode.addClassName(CLASSNAME + "-item-caption");
+ content.addClassName(CLASSNAME + "-item-content");
+
+ touchScrollHandler.addElement(getContainerElement());
+
close();
}
@@ -488,6 +494,7 @@ public class VAccordion extends VTabsheetBase {
protected void removeTab(int index) {
StackItem item = getStackItem(index);
remove(item);
+ touchScrollHandler.removeElement(item.getContainerElement());
}
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java
index e5e7dbba8b..0cd8bc54f4 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/button/VButton.java
@@ -10,6 +10,7 @@ import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Accessibility;
@@ -61,7 +62,9 @@ public class VButton extends FocusWidget implements ClickHandler {
private boolean isCapturing;
/**
- * If <code>true</code>, this widget has focus with the space bar down.
+ * If <code>true</code>, this widget has focus with the space bar down. This
+ * means that we will get events when the button is released, but we should
+ * trigger the button only if the button is still focused at that point.
*/
private boolean isFocusing;
@@ -74,6 +77,14 @@ public class VButton extends FocusWidget implements ClickHandler {
protected int clickShortcut = 0;
+ private HandlerRegistration focusHandlerRegistration;
+ private HandlerRegistration blurHandlerRegistration;
+
+ /**
+ * If caption should be rendered in HTML
+ */
+ protected boolean htmlCaption = false;
+
public VButton() {
super(DOM.createDiv());
setTabIndex(0);
@@ -229,37 +240,28 @@ public class VButton extends FocusWidget implements ClickHandler {
if ((event.getTypeInt() & Event.KEYEVENTS) != 0) {
switch (type) {
case Event.ONKEYDOWN:
+ // Stop propagation when the user starts pressing a button that
+ // we are handling to prevent actions from getting triggered
if (event.getKeyCode() == 32 /* space */) {
isFocusing = true;
event.preventDefault();
+ event.stopPropagation();
+ } else if (event.getKeyCode() == KeyCodes.KEY_ENTER) {
+ event.stopPropagation();
}
break;
case Event.ONKEYUP:
if (isFocusing && event.getKeyCode() == 32 /* space */) {
isFocusing = false;
-
- /*
- * If click shortcut is space then the shortcut handler will
- * take care of the click.
- */
- if (clickShortcut != 32 /* space */) {
- onClick();
- }
-
+ onClick();
+ event.stopPropagation();
event.preventDefault();
}
break;
case Event.ONKEYPRESS:
if (event.getKeyCode() == KeyCodes.KEY_ENTER) {
-
- /*
- * If click shortcut is enter then the shortcut handler will
- * take care of the click.
- */
- if (clickShortcut != KeyCodes.KEY_ENTER) {
- onClick();
- }
-
+ onClick();
+ event.stopPropagation();
event.preventDefault();
}
break;
@@ -336,12 +338,10 @@ public class VButton extends FocusWidget implements ClickHandler {
Accessibility.removeState(getElement(),
Accessibility.STATE_PRESSED);
super.setTabIndex(-1);
- addStyleName(ApplicationConnection.DISABLED_CLASSNAME);
} else {
Accessibility.setState(getElement(),
Accessibility.STATE_PRESSED, "false");
super.setTabIndex(tabIndex);
- removeStyleName(ApplicationConnection.DISABLED_CLASSNAME);
}
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java
index d29eda0d6a..8c5d521445 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/combobox/VFilterSelect.java
@@ -69,7 +69,8 @@ import com.vaadin.terminal.gwt.client.ui.menubar.MenuItem;
*/
@SuppressWarnings("deprecation")
public class VFilterSelect extends Composite implements Field, KeyDownHandler,
- KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable {
+ KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable,
+ SubPartAware {
/**
* Represents a suggestion in the suggestion popup box
@@ -100,6 +101,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* contains an image tag with the rows icon (if an icon has been
* specified) and the caption of the item
*/
+
public String getDisplayString() {
final StringBuffer sb = new StringBuffer();
if (iconUri != null) {
@@ -122,6 +124,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Get a string that represents this item. This is used in the text box.
*/
+
public String getReplacementString() {
return caption;
}
@@ -147,6 +150,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Executes a selection of this item.
*/
+
public void execute() {
onSuggestionSelected(this);
}
@@ -392,6 +396,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt
* .user.client.Event)
*/
+
@Override
public void onBrowserEvent(Event event) {
if (event.getTypeInt() == Event.ONCLICK) {
@@ -449,6 +454,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.user.client.ui.PopupPanel$PositionCallback#setPosition
* (int, int)
*/
+
public void setPosition(int offsetWidth, int offsetHeight) {
int top = -1;
@@ -541,6 +547,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google
* .gwt.event.logical.shared.CloseEvent)
*/
+
@Override
public void onClose(CloseEvent<PopupPanel> event) {
if (event.isAutoClosed()) {
@@ -824,6 +831,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.user.client.ui.TextBoxBase#onBrowserEvent(com.google
* .gwt.user.client.Event)
*/
+
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
@@ -832,8 +840,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
}
- @Override
// Overridden to avoid selecting text when text input is disabled
+ @Override
public void setSelectionRange(int pos, int length) {
if (textInputEnabled) {
super.setSelectionRange(pos, length);
@@ -857,6 +865,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt
* .user.client.Event)
*/
+
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
@@ -951,6 +960,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
public VFilterSelect() {
selectedItemIcon.setStyleName("v-icon");
selectedItemIcon.addLoadHandler(new LoadHandler() {
+
public void onLoad(LoadEvent event) {
if (BrowserInfo.get().isIE8()) {
// IE8 needs some help to discover it should reposition the
@@ -1203,6 +1213,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt
* .event.dom.client.KeyDownEvent)
*/
+
public void onKeyDown(KeyDownEvent event) {
if (enabled && !readonly) {
int keyCode = event.getNativeKeyCode();
@@ -1364,6 +1375,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* @param event
* The KeyUpEvent of the key depressed
*/
+
public void onKeyUp(KeyUpEvent event) {
if (enabled && !readonly) {
switch (event.getNativeKeyCode()) {
@@ -1411,6 +1423,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Listener for popupopener
*/
+
public void onClick(ClickEvent event) {
if (textInputEnabled
&& event.getNativeEvent().getEventTarget().cast() == tb
@@ -1474,6 +1487,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event
* .dom.client.FocusEvent)
*/
+
public void onFocus(FocusEvent event) {
/*
@@ -1567,6 +1581,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*
* @see com.vaadin.terminal.gwt.client.Focusable#focus()
*/
+
public void focus() {
focused = true;
if (prompting && !readonly) {
@@ -1674,4 +1689,22 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
super.onDetach();
suggestionPopup.hide();
}
+
+ public Element getSubPartElement(String subPart) {
+ if ("textbox".equals(subPart)) {
+ return this.tb.getElement();
+ } else if ("button".equals(subPart)) {
+ return this.popupOpener.getElement();
+ }
+ return null;
+ }
+
+ public String getSubPartName(Element subElement) {
+ if (tb.getElement().isOrHasChild(subElement)) {
+ return "textbox";
+ } else if (popupOpener.getElement().isOrHasChild(subElement)) {
+ return "button";
+ }
+ return null;
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/AcceptCriterion.java b/src/com/vaadin/terminal/gwt/client/ui/dd/AcceptCriterion.java
new file mode 100644
index 0000000000..32dac10170
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/AcceptCriterion.java
@@ -0,0 +1,33 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.dd;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation type used to point the server side counterpart for client side
+ * a {@link VAcceptCriterion} class.
+ * <p>
+ * Annotations are used at GWT compilation phase, so remember to rebuild your
+ * widgetset if you do changes for {@link AcceptCriterion} mappings.
+ *
+ * Prior to Vaadin 7, the mapping was done with an annotation on server side
+ * classes.
+ *
+ * @since 7.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface AcceptCriterion {
+ /**
+ * @return the fully qualified class name of the server side counterpart for
+ * the annotated criterion
+ */
+ String value();
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java b/src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java
index 02c1fe5061..97f5eb86fd 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/DDUtil.java
@@ -5,6 +5,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Window;
import com.vaadin.terminal.gwt.client.Util;
public class DDUtil {
@@ -43,8 +44,11 @@ public class DDUtil {
public static VerticalDropLocation getVerticalDropLocation(Element element,
int offsetHeight, int clientY, double topBottomRatio) {
- int absoluteTop = element.getAbsoluteTop();
- int fromTop = clientY - absoluteTop;
+ // Event coordinates are relative to the viewport, element absolute
+ // position is relative to the document. Make element position relative
+ // to viewport by adjusting for viewport scrolling. See #6021
+ int elementTop = element.getAbsoluteTop() - Window.getScrollTop();
+ int fromTop = clientY - elementTop;
float percentageFromTop = (fromTop / (float) offsetHeight);
if (percentageFromTop < topBottomRatio) {
@@ -74,14 +78,17 @@ public class DDUtil {
public static HorizontalDropLocation getHorizontalDropLocation(
Element element, int clientX, double leftRightRatio) {
- int absoluteLeft = element.getAbsoluteLeft();
+ // Event coordinates are relative to the viewport, element absolute
+ // position is relative to the document. Make element position relative
+ // to viewport by adjusting for viewport scrolling. See #6021
+ int elementLeft = element.getAbsoluteLeft() - Window.getScrollLeft();
int offsetWidth = element.getOffsetWidth();
- int fromTop = clientX - absoluteLeft;
+ int fromLeft = clientX - elementLeft;
- float percentageFromTop = (fromTop / (float) offsetWidth);
- if (percentageFromTop < leftRightRatio) {
+ float percentageFromLeft = (fromLeft / (float) offsetWidth);
+ if (percentageFromLeft < leftRightRatio) {
return HorizontalDropLocation.LEFT;
- } else if (percentageFromTop > 1 - leftRightRatio) {
+ } else if (percentageFromLeft > 1 - leftRightRatio) {
return HorizontalDropLocation.RIGHT;
} else {
return HorizontalDropLocation.CENTER;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VAcceptAll.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VAcceptAll.java
index 51782c002d..07e931fb02 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VAcceptAll.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VAcceptAll.java
@@ -8,6 +8,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.AcceptAll")
final public class VAcceptAll extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VAnd.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VAnd.java
index 65c67e6b8a..727c30075c 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VAnd.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VAnd.java
@@ -8,6 +8,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.And")
final public class VAnd extends VAcceptCriterion implements VAcceptCallback {
private boolean b1;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VContainsDataFlavor.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VContainsDataFlavor.java
index 4a95034d4a..5786068174 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VContainsDataFlavor.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VContainsDataFlavor.java
@@ -8,6 +8,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.ContainsDataFlavor")
final public class VContainsDataFlavor extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java
index aabbf58b24..58550af918 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VDragSourceIs.java
@@ -12,6 +12,7 @@ import com.vaadin.terminal.gwt.client.UIDL;
*
* @since 6.3
*/
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.SourceIs")
final public class VDragSourceIs extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java
index 90e2b033c9..3fc54e6fd3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VIsOverId.java
@@ -10,6 +10,7 @@ import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.ConnectorMap;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.ui.AbstractSelect.TargetItemIs")
final public class VIsOverId extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java
index eb55c1a91c..5f1fe978b5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VItemIdIs.java
@@ -9,6 +9,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.ui.AbstractSelect.AcceptItem")
final public class VItemIdIs extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VLazyInitItemIdentifiers.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VLazyInitItemIdentifiers.java
index b824c1cb65..e972371b9f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VLazyInitItemIdentifiers.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VLazyInitItemIdentifiers.java
@@ -13,11 +13,23 @@ import com.vaadin.terminal.gwt.client.UIDL;
/**
*
*/
-final public class VLazyInitItemIdentifiers extends VAcceptCriterion {
+public class VLazyInitItemIdentifiers extends VAcceptCriterion {
private boolean loaded = false;
private HashSet<String> hashSet;
private VDragEvent lastDragEvent;
+ @AcceptCriterion("com.vaadin.ui.Table.TableDropCriterion")
+ final public static class VTableLazyInitItemIdentifiers extends
+ VLazyInitItemIdentifiers {
+ // all logic in superclass
+ }
+
+ @AcceptCriterion("com.vaadin.ui.Tree.TreeDropCriterion")
+ final public static class VTreeLazyInitItemIdentifiers extends
+ VLazyInitItemIdentifiers {
+ // all logic in superclass
+ }
+
@Override
public void accept(final VDragEvent drag, UIDL configuration,
final VAcceptCallback callback) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VNot.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VNot.java
index f4ba868497..e91ad6149a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VNot.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VNot.java
@@ -13,6 +13,7 @@ import com.vaadin.terminal.gwt.client.VConsole;
* TODO implementation could now be simplified/optimized
*
*/
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.Not")
final public class VNot extends VAcceptCriterion {
private boolean b1;
private VAcceptCriterion crit1;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VOr.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VOr.java
index e47447b7fc..3664326568 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VOr.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VOr.java
@@ -11,6 +11,7 @@ import com.vaadin.terminal.gwt.client.UIDL;
/**
*
*/
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.Or")
final public class VOr extends VAcceptCriterion implements VAcceptCallback {
private boolean accepted;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VServerAccept.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VServerAccept.java
index bccb6656aa..e679b64369 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VServerAccept.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VServerAccept.java
@@ -8,6 +8,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.ServerSideCriterion")
final public class VServerAccept extends VAcceptCriterion {
@Override
public void accept(final VDragEvent drag, UIDL configuration,
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java
index 430b422b34..9bbabe9d29 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VSourceIsTarget.java
@@ -9,6 +9,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.ComponentConnector;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.SourceIsTarget")
final public class VSourceIsTarget extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetDetailIs.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetDetailIs.java
index 713a0d6646..7d92359f7d 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetDetailIs.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetDetailIs.java
@@ -8,6 +8,7 @@ package com.vaadin.terminal.gwt.client.ui.dd;
import com.vaadin.terminal.gwt.client.UIDL;
+@AcceptCriterion("com.vaadin.event.dd.acceptcriteria.TargetDetailIs")
final public class VTargetDetailIs extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java
index f69fa85290..3db44f3162 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VTargetInSubtree.java
@@ -11,6 +11,7 @@ import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.ui.tree.VTree;
import com.vaadin.terminal.gwt.client.ui.tree.VTree.TreeNode;
+@AcceptCriterion("com.vaadin.ui.Tree.TargetInSubtree")
final public class VTargetInSubtree extends VAcceptCriterion {
@Override
diff --git a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java
index 57f6835bcc..2a78cc4433 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/DragAndDropWrapperConnector.java
@@ -57,6 +57,9 @@ public class DragAndDropWrapperConnector extends CustomComponentConnector
getWidget().initDragStartMode();
getWidget().html5DataFlavors = uidl
.getMapAttribute(VDragAndDropWrapper.HTML5_DATA_FLAVORS);
+
+ // Used to prevent wrapper from stealing tooltips when not defined
+ getWidget().hasTooltip = getState().hasDescription();
}
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java
index d09b81e1e1..4c36e92bbb 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/draganddropwrapper/VDragAndDropWrapper.java
@@ -60,6 +60,8 @@ public class VDragAndDropWrapper extends VCustomComponent implements
private static final String CLASSNAME = "v-ddwrapper";
protected static final String DRAGGABLE = "draggable";
+ boolean hasTooltip = false;
+
public VDragAndDropWrapper() {
super();
sinkEvents(VTooltip.TOOLTIP_EVENTS);
@@ -67,6 +69,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
hookHtml5Events(getElement());
setStyleName(CLASSNAME);
addDomHandler(new MouseDownHandler() {
+
public void onMouseDown(MouseDownEvent event) {
if (startDrag(event.getNativeEvent())) {
event.preventDefault(); // prevent text selection
@@ -75,6 +78,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
}, MouseDownEvent.getType());
addDomHandler(new TouchStartHandler() {
+
public void onTouchStart(TouchStartEvent event) {
if (startDrag(event.getNativeEvent())) {
/*
@@ -92,7 +96,8 @@ public class VDragAndDropWrapper extends VCustomComponent implements
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
- if (client != null) {
+ if (hasTooltip && client != null) {
+ // Override child tooltips if the wrapper has a tooltip defined
client.handleTooltipEvent(event, this);
}
}
@@ -172,6 +177,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
private boolean uploading;
private ReadyStateChangeHandler readyStateChangeHandler = new ReadyStateChangeHandler() {
+
public void onReadyStateChange(XMLHttpRequest xhr) {
if (xhr.getReadyState() == XMLHttpRequest.DONE) {
// visit server for possible
@@ -269,6 +275,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
try {
dragleavetimer = new Timer() {
+
@Override
public void run() {
// Yes, dragleave happens before drop. Makes no sense to me.
@@ -455,6 +462,7 @@ public class VDragAndDropWrapper extends VCustomComponent implements
if (detailsChanged) {
currentlyValid = false;
validate(new VAcceptCallback() {
+
public void accepted(VDragEvent event) {
dragAccepted(drag);
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java b/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java
index e3a0c9b321..81f24a8e7e 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/form/VForm.java
@@ -4,7 +4,6 @@
package com.vaadin.terminal.gwt.client.ui.form;
-import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.shared.HandlerRegistration;
@@ -27,7 +26,6 @@ public class VForm extends ComplexPanel implements KeyDownHandler {
Widget lo;
Element legend = DOM.createLegend();
Element caption = DOM.createSpan();
- private Element errorIndicatorElement = DOM.createDiv();
Element desc = DOM.createDiv();
Icon icon;
VErrorMessage errorMessage = new VErrorMessage();
@@ -52,9 +50,6 @@ public class VForm extends ComplexPanel implements KeyDownHandler {
setStyleName(CLASSNAME);
fieldSet.appendChild(legend);
legend.appendChild(caption);
- errorIndicatorElement.setClassName("v-errorindicator");
- errorIndicatorElement.getStyle().setDisplay(Display.NONE);
- errorIndicatorElement.setInnerText(" "); // needed for IE
desc.setClassName("v-form-description");
fieldSet.appendChild(desc); // Adding description for initial padding
// measurements, removed later if no
diff --git a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java
index 01ac4fab6a..dd6e741126 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/nativebutton/VNativeButton.java
@@ -127,11 +127,4 @@ public class VNativeButton extends Button implements ClickHandler {
clickPending = false;
}
- @Override
- public void setEnabled(boolean enabled) {
- if (isEnabled() != enabled) {
- super.setEnabled(enabled);
- setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled);
- }
- }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
index 0d222044ba..fb853b8a55 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/notification/VNotification.java
@@ -43,6 +43,8 @@ public class VNotification extends VOverlay {
public static final String STYLE_SYSTEM = "system";
private static final int FADE_ANIMATION_INTERVAL = 50; // == 20 fps
+ private static final ArrayList<VNotification> notifications = new ArrayList<VNotification>();
+
private int startOpacity = 90;
private int fadeMsec = 400;
private int delayMsec = 1000;
@@ -159,6 +161,7 @@ public class VNotification extends VOverlay {
addStyleDependentName(style);
}
super.show();
+ notifications.add(this);
setPosition(position);
/**
* Android 4 fails to render notifications correctly without a little
@@ -180,6 +183,7 @@ public class VNotification extends VOverlay {
temporaryStyle = null;
}
super.hide();
+ notifications.remove(this);
fireEvent(new HideEvent(this));
}
@@ -435,4 +439,19 @@ public class VNotification extends VOverlay {
public interface EventListener extends java.util.EventListener {
public void notificationHidden(HideEvent event);
}
+
+ /**
+ * Moves currently visible notifications to the top of the event preview
+ * stack. Can be called when opening other overlays such as subwindows to
+ * ensure the notifications receive the events they need and don't linger
+ * indefinitely. See #7136.
+ *
+ * TODO Should this be a generic Overlay feature instead?
+ */
+ public static void bringNotificationsToFront() {
+ for (VNotification notification : notifications) {
+ DOM.removeEventPreview(notification);
+ DOM.addEventPreview(notification);
+ }
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java
index 5b97fc110f..d9096526f3 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/panel/PanelConnector.java
@@ -111,6 +111,8 @@ public class PanelConnector extends AbstractComponentContainerConnector
getWidget().captionNode.setClassName(captionClass);
getWidget().contentNode.setClassName(contentClass);
getWidget().bottomDecoration.setClassName(decoClass);
+
+ getWidget().makeScrollable();
}
if (!isRealUpdate(uidl)) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java
index e2d3d443a0..6a06367acd 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/panel/VPanel.java
@@ -6,8 +6,6 @@ package com.vaadin.terminal.gwt.client.ui.panel;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
-import com.google.gwt.event.dom.client.TouchStartEvent;
-import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -18,6 +16,7 @@ import com.vaadin.terminal.gwt.client.ui.Icon;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler;
public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
Focusable {
@@ -46,7 +45,7 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
int scrollLeft;
- private TouchScrollDelegate touchScrollDelegate;
+ private TouchScrollHandler touchScrollHandler;
public VPanel() {
super();
@@ -74,11 +73,11 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
setStyleName(CLASSNAME);
DOM.sinkEvents(getElement(), Event.ONKEYDOWN);
DOM.sinkEvents(contentNode, Event.ONSCROLL | Event.TOUCHEVENTS);
- addHandler(new TouchStartHandler() {
- public void onTouchStart(TouchStartEvent event) {
- getTouchScrollDelegate().onTouchStart(event);
- }
- }, TouchStartEvent.getType());
+
+ contentNode.getStyle().setProperty("position", "relative");
+ getElement().getStyle().setProperty("overflow", "hidden");
+
+ makeScrollable();
}
/**
@@ -100,6 +99,7 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
*
* @see com.vaadin.terminal.gwt.client.Focusable#focus()
*/
+
public void focus() {
setFocus(true);
@@ -174,16 +174,17 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
}
}
- protected TouchScrollDelegate getTouchScrollDelegate() {
- if (touchScrollDelegate == null) {
- touchScrollDelegate = new TouchScrollDelegate(contentNode);
- }
- return touchScrollDelegate;
-
- }
-
public ShortcutActionHandler getShortcutActionHandler() {
return shortcutHandler;
}
+ /**
+ * Ensures the panel is scrollable eg. after style name changes
+ */
+ void makeScrollable() {
+ if (touchScrollHandler == null) {
+ touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
+ }
+ touchScrollHandler.addElement(contentNode);
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/PageClientRpc.java b/src/com/vaadin/terminal/gwt/client/ui/root/PageClientRpc.java
new file mode 100644
index 0000000000..a02ecc8ded
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/PageClientRpc.java
@@ -0,0 +1,13 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.root;
+
+import com.vaadin.terminal.gwt.client.communication.ClientRpc;
+
+public interface PageClientRpc extends ClientRpc {
+
+ public void setTitle(String title);
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
index 9be41a9623..1a62e566ad 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/RootConnector.java
@@ -61,6 +61,11 @@ public class RootConnector extends AbstractComponentContainerConnector
@Override
protected void init() {
super.init();
+ registerRpc(PageClientRpc.class, new PageClientRpc() {
+ public void setTitle(String title) {
+ com.google.gwt.user.client.Window.setTitle(title);
+ }
+ });
}
public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
@@ -93,12 +98,9 @@ public class RootConnector extends AbstractComponentContainerConnector
}
getWidget().setStyleName(styles.trim());
- clickEventHandler.handleEventHandlerRegistration();
+ getWidget().makeScrollable();
- if (!getWidget().isEmbedded() && getState().getCaption() != null) {
- // only change window title if we're in charge of the whole page
- com.google.gwt.user.client.Window.setTitle(getState().getCaption());
- }
+ clickEventHandler.handleEventHandlerRegistration();
// Process children
int childIndex = 0;
@@ -168,9 +170,6 @@ public class RootConnector extends AbstractComponentContainerConnector
getWidget().id, client);
}
getWidget().actionHandler.updateActionMap(childUidl);
- } else if (tag == "execJS") {
- String script = childUidl.getStringAttribute("script");
- VRoot.eval(script);
} else if (tag == "notifications") {
for (final Iterator<?> it = childUidl.getChildIterator(); it
.hasNext();) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
index 12a69d5556..0af8919280 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/root/VRoot.java
@@ -7,6 +7,7 @@ package com.vaadin.terminal.gwt.client.ui.root;
import java.util.ArrayList;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
@@ -26,6 +27,8 @@ import com.vaadin.terminal.gwt.client.Focusable;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
import com.vaadin.terminal.gwt.client.ui.textfield.VTextField;
@@ -37,21 +40,36 @@ public class VRoot extends SimplePanel implements ResizeHandler,
public static final String FRAGMENT_VARIABLE = "fragment";
+ public static final String BROWSER_HEIGHT_VAR = "browserHeight";
+
+ public static final String BROWSER_WIDTH_VAR = "browserWidth";
+
private static final String CLASSNAME = "v-view";
public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";
+ private static int MONITOR_PARENT_TIMER_INTERVAL = 1000;
+
String theme;
String id;
ShortcutActionHandler actionHandler;
- /** stored width for IE resize optimization */
- private int width;
+ /*
+ * Last known window size used to detect whether VView should be layouted
+ * again. Detection must check window size, because the VView size might be
+ * fixed and thus not automatically adapt to changed window sizes.
+ */
+ private int windowWidth;
+ private int windowHeight;
- /** stored height for IE resize optimization */
- private int height;
+ /*
+ * Last know view size used to detect whether new dimensions should be sent
+ * to the server.
+ */
+ private int viewWidth;
+ private int viewHeight;
ApplicationConnection connection;
@@ -59,13 +77,19 @@ public class VRoot extends SimplePanel implements ResizeHandler,
public static final String CLICK_EVENT_ID = "click";
/**
- * We are postponing resize process with IE. IE bugs with scrollbars in some
- * situations, that causes false onWindowResized calls. With Timer we will
- * give IE some time to decide if it really wants to keep current size
- * (scrollbars).
+ * Keep track of possible parent size changes when an embedded application.
+ *
+ * Uses {@link #parentWidth} and {@link #parentHeight} as an optimization to
+ * keep track of when there is a real change.
*/
private Timer resizeTimer;
+ /** stored width of parent for embedded application auto-resize */
+ private int parentWidth;
+
+ /** stored height of parent for embedded application auto-resize */
+ private int parentHeight;
+
int scrollTop;
int scrollLeft;
@@ -85,6 +109,8 @@ public class VRoot extends SimplePanel implements ResizeHandler,
private HandlerRegistration historyHandlerRegistration;
+ private TouchScrollHandler touchScrollHandler;
+
/**
* The current URI fragment, used to avoid sending updates if nothing has
* changed.
@@ -96,6 +122,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,
* whenever the value changes.
*/
private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
+
public void onValueChange(ValueChangeEvent<String> event) {
String newFragment = event.getValue();
@@ -110,9 +137,9 @@ public class VRoot extends SimplePanel implements ResizeHandler,
private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
new ScheduledCommand() {
+
public void execute() {
- windowSizeMaybeChanged(Window.getClientWidth(),
- Window.getClientHeight());
+ performSizeCheck();
}
});
@@ -124,6 +151,29 @@ public class VRoot extends SimplePanel implements ResizeHandler,
// Allow focusing the view by using the focus() method, the view
// should not be in the document focus flow
getElement().setTabIndex(-1);
+ makeScrollable();
+ }
+
+ /**
+ * Start to periodically monitor for parent element resizes if embedded
+ * application (e.g. portlet).
+ */
+ @Override
+ protected void onLoad() {
+ super.onLoad();
+ if (isMonitoringParentSize()) {
+ resizeTimer = new Timer() {
+
+ @Override
+ public void run() {
+ // trigger check to see if parent size has changed,
+ // recalculate layouts
+ performSizeCheck();
+ resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL);
+ }
+ };
+ resizeTimer.schedule(MONITOR_PARENT_TIMER_INTERVAL);
+ }
}
@Override
@@ -142,32 +192,95 @@ public class VRoot extends SimplePanel implements ResizeHandler,
}
/**
- * Called when the window might have been resized.
+ * Stop monitoring for parent element resizes.
+ */
+
+ @Override
+ protected void onUnload() {
+ if (resizeTimer != null) {
+ resizeTimer.cancel();
+ resizeTimer = null;
+ }
+ super.onUnload();
+ }
+
+ /**
+ * Called when the window or parent div might have been resized.
*
- * @param newWidth
+ * This immediately checks the sizes of the window and the parent div (if
+ * monitoring it) and triggers layout recalculation if they have changed.
+ */
+ protected void performSizeCheck() {
+ windowSizeMaybeChanged(Window.getClientWidth(),
+ Window.getClientHeight());
+ }
+
+ /**
+ * Called when the window or parent div might have been resized.
+ *
+ * This immediately checks the sizes of the window and the parent div (if
+ * monitoring it) and triggers layout recalculation if they have changed.
+ *
+ * @param newWindowWidth
* The new width of the window
- * @param newHeight
+ * @param newWindowHeight
* The new height of the window
+ *
+ * @deprecated use {@link #performSizeCheck()}
*/
- protected void windowSizeMaybeChanged(int newWidth, int newHeight) {
+ @Deprecated
+ protected void windowSizeMaybeChanged(int newWindowWidth,
+ int newWindowHeight) {
boolean changed = false;
ComponentConnector connector = ConnectorMap.get(connection)
.getConnector(this);
- if (width != newWidth) {
- width = newWidth;
+ if (windowWidth != newWindowWidth) {
+ windowWidth = newWindowWidth;
changed = true;
- connector.getLayoutManager().reportOuterWidth(connector, newWidth);
- VConsole.log("New window width: " + width);
+ connector.getLayoutManager().reportOuterWidth(connector,
+ newWindowWidth);
+ VConsole.log("New window width: " + windowWidth);
}
- if (height != newHeight) {
- height = newHeight;
+ if (windowHeight != newWindowHeight) {
+ windowHeight = newWindowHeight;
changed = true;
- connector.getLayoutManager()
- .reportOuterHeight(connector, newHeight);
- VConsole.log("New window height: " + height);
+ connector.getLayoutManager().reportOuterHeight(connector,
+ newWindowHeight);
+ VConsole.log("New window height: " + windowHeight);
+ }
+ Element parentElement = getElement().getParentElement();
+ if (isMonitoringParentSize() && parentElement != null) {
+ // check also for parent size changes
+ int newParentWidth = parentElement.getClientWidth();
+ int newParentHeight = parentElement.getClientHeight();
+ if (parentWidth != newParentWidth) {
+ parentWidth = newParentWidth;
+ changed = true;
+ VConsole.log("New parent width: " + parentWidth);
+ }
+ if (parentHeight != newParentHeight) {
+ parentHeight = newParentHeight;
+ changed = true;
+ VConsole.log("New parent height: " + parentHeight);
+ }
}
if (changed) {
- VConsole.log("Running layout functions due to window resize");
+ /*
+ * If the window size has changed, layout the VView again and send
+ * new size to the server if the size changed. (Just checking VView
+ * size would cause us to ignore cases when a relatively sized VView
+ * should shrink as the content's size is fixed and would thus not
+ * automatically shrink.)
+ */
+ VConsole.log("Running layout functions due to window or parent resize");
+
+ // update size to avoid (most) redundant re-layout passes
+ // there can still be an extra layout recalculation if webkit
+ // overflow fix updates the size in a deferred block
+ if (isMonitoringParentSize() && parentElement != null) {
+ parentWidth = parentElement.getClientWidth();
+ parentHeight = parentElement.getClientHeight();
+ }
sendClientResized();
@@ -188,21 +301,6 @@ public class VRoot extends SimplePanel implements ResizeHandler,
}-*/;
/**
- * Evaluate the given script in the browser document.
- *
- * @param script
- * Script to be executed.
- */
- static native void eval(String script)
- /*-{
- try {
- if (script == null) return;
- $wnd.eval(script);
- } catch (e) {
- }
- }-*/;
-
- /**
* Returns true if the body is NOT generated, i.e if someone else has made
* the page that we're running in. Otherwise we're in charge of the whole
* page.
@@ -214,6 +312,17 @@ public class VRoot extends SimplePanel implements ResizeHandler,
.contains(ApplicationConnection.GENERATED_BODY_CLASSNAME);
}
+ /**
+ * Returns true if the size of the parent should be checked periodically and
+ * the application should react to its changes.
+ *
+ * @return true if size of parent should be tracked
+ */
+ protected boolean isMonitoringParentSize() {
+ // could also perform a more specific check (Liferay portlet)
+ return isEmbedded();
+ }
+
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
@@ -251,14 +360,19 @@ public class VRoot extends SimplePanel implements ResizeHandler,
* com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google
* .gwt.event.logical.shared.ResizeEvent)
*/
+
public void onResize(ResizeEvent event) {
- onResize();
+ triggerSizeChangeCheck();
}
/**
* Called when a resize event is received.
+ *
+ * This may trigger a lazy refresh or perform the size check immediately
+ * depending on the browser used and whether the server side requests
+ * resizes to be lazy.
*/
- void onResize() {
+ private void triggerSizeChangeCheck() {
/*
* IE (pre IE9 at least) will give us some false resize events due to
* problems with scrollbars. Firefox 3 might also produce some extra
@@ -274,8 +388,7 @@ public class VRoot extends SimplePanel implements ResizeHandler,
if (lazy) {
delayedResizeExecutor.trigger();
} else {
- windowSizeMaybeChanged(Window.getClientWidth(),
- Window.getClientHeight());
+ performSizeCheck();
}
}
@@ -283,8 +396,19 @@ public class VRoot extends SimplePanel implements ResizeHandler,
* Send new dimensions to the server.
*/
private void sendClientResized() {
- connection.updateVariable(id, "height", height, false);
- connection.updateVariable(id, "width", width, immediate);
+ Element parentElement = getElement().getParentElement();
+ int viewHeight = parentElement.getClientHeight();
+ int viewWidth = parentElement.getClientWidth();
+
+ connection.updateVariable(id, "height", viewHeight, false);
+ connection.updateVariable(id, "width", viewWidth, false);
+
+ int windowWidth = Window.getClientWidth();
+ int windowHeight = Window.getClientHeight();
+
+ connection.updateVariable(id, BROWSER_WIDTH_VAR, windowWidth, false);
+ connection.updateVariable(id, BROWSER_HEIGHT_VAR, windowHeight,
+ immediate);
}
public native static void goTo(String url)
@@ -319,4 +443,13 @@ public class VRoot extends SimplePanel implements ResizeHandler,
getElement().focus();
}
+ /**
+ * Ensures the root is scrollable eg. after style name changes.
+ */
+ void makeScrollable() {
+ if (touchScrollHandler == null) {
+ touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
+ }
+ touchScrollHandler.addElement(getElement());
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java
index 9ff614252d..5c7ee7a784 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/slider/VSlider.java
@@ -18,6 +18,7 @@ import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.ContainerResizedListener;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VTooltip;
import com.vaadin.terminal.gwt.client.ui.Field;
import com.vaadin.terminal.gwt.client.ui.SimpleFocusablePanel;
import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
@@ -51,6 +52,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
private final HTML feedback = new HTML("", false);
private final VOverlay feedbackPopup = new VOverlay(true, false, true) {
+
@Override
public void show() {
super.show();
@@ -112,6 +114,8 @@ public class VSlider extends SimpleFocusablePanel implements Field,
feedbackPopup.addStyleName(CLASSNAME + "-feedback");
feedbackPopup.setWidget(feedback);
+
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
}
void setFeedbackValue(double value) {
@@ -139,8 +143,12 @@ public class VSlider extends SimpleFocusablePanel implements Field,
void buildBase() {
final String styleAttribute = vertical ? "height" : "width";
+ final String oppositeStyleAttribute = vertical ? "width" : "height";
final String domProperty = vertical ? "offsetHeight" : "offsetWidth";
+ // clear unnecessary opposite style attribute
+ DOM.setStyleAttribute(base, oppositeStyleAttribute, "");
+
final Element p = DOM.getParent(getElement());
if (DOM.getElementPropertyInt(p, domProperty) > 50) {
if (vertical) {
@@ -153,6 +161,7 @@ public class VSlider extends SimpleFocusablePanel implements Field,
// (supposedly) been drawn completely.
DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px");
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
final Element p = DOM.getParent(getElement());
if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) {
@@ -173,9 +182,14 @@ public class VSlider extends SimpleFocusablePanel implements Field,
void buildHandle() {
final String handleAttribute = vertical ? "marginTop" : "marginLeft";
+ final String oppositeHandleAttribute = vertical ? "marginLeft"
+ : "marginTop";
DOM.setStyleAttribute(handle, handleAttribute, "0");
+ // clear unnecessary opposite handle attribute
+ DOM.setStyleAttribute(handle, oppositeHandleAttribute, "");
+
// Restore visibility
DOM.setStyleAttribute(handle, "visibility", "visible");
@@ -277,6 +291,9 @@ public class VSlider extends SimpleFocusablePanel implements Field,
event.preventDefault(); // avoid simulated events
event.stopPropagation();
}
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
}
private void processMouseWheelEvent(final Event event) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
index 10e5dbe37a..e33755bc9b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelConnector.java
@@ -127,6 +127,12 @@ public abstract class AbstractSplitPanelConnector extends
getWidget().setStylenames();
+ getWidget().minimumPosition = splitterState.getMinPosition()
+ + splitterState.getMinPositionUnit();
+
+ getWidget().maximumPosition = splitterState.getMaxPosition()
+ + splitterState.getMaxPositionUnit();
+
getWidget().position = splitterState.getPosition()
+ splitterState.getPositionUnit();
@@ -136,6 +142,7 @@ public abstract class AbstractSplitPanelConnector extends
getLayoutManager().setNeedsLayout(this);
+ getWidget().makeScrollable();
}
public void layout() {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java
index 8b80eed840..db3a39d3a5 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/AbstractSplitPanelState.java
@@ -49,6 +49,10 @@ public class AbstractSplitPanelState extends ComponentState {
public static class SplitterState implements Serializable {
private float position;
private String positionUnit;
+ private float minPosition;
+ private String minPositionUnit;
+ private float maxPosition;
+ private String maxPositionUnit;
private boolean positionReversed = false;
private boolean locked = false;
@@ -68,6 +72,38 @@ public class AbstractSplitPanelState extends ComponentState {
this.positionUnit = positionUnit;
}
+ public float getMinPosition() {
+ return minPosition;
+ }
+
+ public void setMinPosition(float minPosition) {
+ this.minPosition = minPosition;
+ }
+
+ public String getMinPositionUnit() {
+ return minPositionUnit;
+ }
+
+ public void setMinPositionUnit(String minPositionUnit) {
+ this.minPositionUnit = minPositionUnit;
+ }
+
+ public float getMaxPosition() {
+ return maxPosition;
+ }
+
+ public void setMaxPosition(float maxPosition) {
+ this.maxPosition = maxPosition;
+ }
+
+ public String getMaxPositionUnit() {
+ return maxPositionUnit;
+ }
+
+ public void setMaxPositionUnit(String maxPositionUnit) {
+ this.maxPositionUnit = maxPositionUnit;
+ }
+
public boolean isPositionReversed() {
return positionReversed;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java
index 166e79e92e..e2f30c6676 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java
@@ -4,6 +4,7 @@
package com.vaadin.terminal.gwt.client.ui.splitpanel;
+import java.util.Collections;
import java.util.List;
import com.google.gwt.dom.client.Node;
@@ -31,6 +32,7 @@ import com.vaadin.terminal.gwt.client.LayoutManager;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.terminal.gwt.client.ui.VOverlay;
import com.vaadin.terminal.gwt.client.ui.splitpanel.VAbstractSplitPanel.SplitterMoveHandler.SplitterMoveEvent;
@@ -76,7 +78,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
private boolean positionReversed = false;
- List<String> componentStyleNames;
+ List<String> componentStyleNames = Collections.emptyList();
private Element draggingCurtain;
@@ -87,12 +89,16 @@ public class VAbstractSplitPanel extends ComplexPanel {
/* The current position of the split handle in either percentages or pixels */
String position;
+ String maximumPosition;
+
+ String minimumPosition;
+
+ private TouchScrollHandler touchScrollHandler;
+
protected Element scrolledContainer;
protected int origScrollTop;
- private TouchScrollDelegate touchScrollDelegate;
-
public VAbstractSplitPanel() {
this(ORIENTATION_HORIZONTAL);
}
@@ -116,6 +122,8 @@ public class VAbstractSplitPanel extends ComplexPanel {
setOrientation(orientation);
sinkEvents(Event.MOUSEEVENTS);
+ makeScrollable();
+
addDomHandler(new TouchCancelHandler() {
public void onTouchCancel(TouchCancelEvent event) {
// TODO When does this actually happen??
@@ -127,11 +135,8 @@ public class VAbstractSplitPanel extends ComplexPanel {
Node target = event.getTouches().get(0).getTarget().cast();
if (splitter.isOrHasChild(target)) {
onMouseDown(Event.as(event.getNativeEvent()));
- } else {
- getTouchScrollDelegate().onTouchStart(event);
}
}
-
}, TouchStartEvent.getType());
addDomHandler(new TouchMoveHandler() {
public void onTouchMove(TouchMoveEvent event) {
@@ -150,14 +155,6 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
- private TouchScrollDelegate getTouchScrollDelegate() {
- if (touchScrollDelegate == null) {
- touchScrollDelegate = new TouchScrollDelegate(firstContainer,
- secondContainer);
- }
- return touchScrollDelegate;
- }
-
protected void constructDom() {
DOM.appendChild(splitter, DOM.createDiv()); // for styling
DOM.appendChild(getElement(), wrapper);
@@ -172,9 +169,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
DOM.setStyleAttribute(splitter, "position", "absolute");
DOM.setStyleAttribute(secondContainer, "position", "absolute");
- DOM.setStyleAttribute(firstContainer, "overflow", "auto");
- DOM.setStyleAttribute(secondContainer, "overflow", "auto");
-
+ setStylenames();
}
private void setOrientation(int orientation) {
@@ -190,11 +185,6 @@ public class VAbstractSplitPanel extends ComplexPanel {
DOM.setStyleAttribute(firstContainer, "width", "100%");
DOM.setStyleAttribute(secondContainer, "width", "100%");
}
-
- DOM.setElementProperty(firstContainer, "className", CLASSNAME
- + "-first-container");
- DOM.setElementProperty(secondContainer, "className", CLASSNAME
- + "-second-container");
}
@Override
@@ -232,11 +222,109 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
}
+ /**
+ * Converts given split position string (in pixels or percentage) to a
+ * floating point pixel value.
+ *
+ * @param pos
+ * @return
+ */
+ private float convertToPixels(String pos) {
+ float posAsFloat;
+ if (pos.indexOf("%") > 0) {
+ posAsFloat = Math.round(Float.parseFloat(pos.substring(0,
+ pos.length() - 1))
+ / 100
+ * (orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
+ : getOffsetHeight()));
+ } else {
+ posAsFloat = Float.parseFloat(pos.substring(0, pos.length() - 2));
+ }
+ return posAsFloat;
+ }
+
+ /**
+ * Converts given split position string (in pixels or percentage) to a float
+ * percentage value.
+ *
+ * @param pos
+ * @return
+ */
+ private float convertToPercentage(String pos) {
+ float posAsFloat = 0;
+
+ if (pos.indexOf("px") > 0) {
+ int posAsInt = Integer.parseInt(pos.substring(0, pos.length() - 2));
+ int offsetLength = orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
+ : getOffsetHeight();
+
+ // 100% needs special handling
+ if (posAsInt + getSplitterSize() >= offsetLength) {
+ posAsInt = offsetLength;
+ }
+ posAsFloat = ((float) posAsInt / (float) offsetLength * 100);
+
+ } else {
+ posAsFloat = Float.parseFloat(pos.substring(0, pos.length() - 1));
+ }
+ return posAsFloat;
+ }
+
+ /**
+ * Returns the given position clamped to the range between current minimum
+ * and maximum positions.
+ *
+ * TODO Should this be in the connector?
+ *
+ * @param pos
+ * Position of the splitter as a CSS string, either pixels or a
+ * percentage.
+ * @return minimumPosition if pos is less than minimumPosition;
+ * maximumPosition if pos is greater than maximumPosition; pos
+ * otherwise.
+ */
+ private String checkSplitPositionLimits(String pos) {
+ float positionAsFloat = convertToPixels(pos);
+
+ if (maximumPosition != null
+ && convertToPixels(maximumPosition) < positionAsFloat) {
+ pos = maximumPosition;
+ } else if (minimumPosition != null
+ && convertToPixels(minimumPosition) > positionAsFloat) {
+ pos = minimumPosition;
+ }
+ return pos;
+ }
+
+ /**
+ * Converts given string to the same units as the split position is.
+ *
+ * @param pos
+ * position to be converted
+ * @return converted position string
+ */
+ private String convertToPositionUnits(String pos) {
+ if (position.indexOf("%") != -1 && pos.indexOf("%") == -1) {
+ // position is in percentage, pos in pixels
+ pos = convertToPercentage(pos) + "%";
+ } else if (position.indexOf("px") > 0 && pos.indexOf("px") == -1) {
+ // position is in pixels and pos in percentage
+ pos = convertToPixels(pos) + "px";
+ }
+
+ return pos;
+ }
+
void setSplitPosition(String pos) {
if (pos == null) {
return;
}
+ pos = checkSplitPositionLimits(pos);
+ if (!pos.equals(position)) {
+ position = convertToPositionUnits(pos);
+ }
+
// Convert percentage values to pixels
if (pos.indexOf("%") > 0) {
int size = orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
@@ -375,7 +463,6 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
break;
}
-
}
void setFirstWidget(Widget w) {
@@ -481,16 +568,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
if (position.indexOf("%") > 0) {
- float pos = newX;
- // 100% needs special handling
- if (newX + getSplitterSize() >= getOffsetWidth()) {
- pos = getOffsetWidth();
- }
- // Reversed position
- if (positionReversed) {
- pos = getOffsetWidth() - pos - getSplitterSize();
- }
- position = (pos / getOffsetWidth() * 100) + "%";
+ position = convertToPositionUnits(newX + "px");
} else {
// Reversed position
if (positionReversed) {
@@ -523,16 +601,7 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
if (position.indexOf("%") > 0) {
- float pos = newY;
- // 100% needs special handling
- if (newY + getSplitterSize() >= getOffsetHeight()) {
- pos = getOffsetHeight();
- }
- // Reversed position
- if (positionReversed) {
- pos = getOffsetHeight() - pos - getSplitterSize();
- }
- position = pos / getOffsetHeight() * 100 + "%";
+ position = convertToPositionUnits(newY + "px");
} else {
// Reversed position
if (positionReversed) {
@@ -659,30 +728,24 @@ public class VAbstractSplitPanel extends ComplexPanel {
}
void setStylenames() {
- final String splitterSuffix = (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter"
- : "-vsplitter");
- final String firstContainerSuffix = "-first-container";
- final String secondContainerSuffix = "-second-container";
- String lockedSuffix = "";
-
- String splitterStyle = CLASSNAME + splitterSuffix;
- String firstStyle = CLASSNAME + firstContainerSuffix;
- String secondStyle = CLASSNAME + secondContainerSuffix;
-
- if (locked) {
- splitterStyle = CLASSNAME + splitterSuffix + "-locked";
- lockedSuffix = "-locked";
- }
- for (String style : componentStyleNames) {
- splitterStyle += " " + CLASSNAME + splitterSuffix + "-" + style
- + lockedSuffix;
- firstStyle += " " + CLASSNAME + firstContainerSuffix + "-" + style;
- secondStyle += " " + CLASSNAME + secondContainerSuffix + "-"
- + style;
- }
- DOM.setElementProperty(splitter, "className", splitterStyle);
- DOM.setElementProperty(firstContainer, "className", firstStyle);
- DOM.setElementProperty(secondContainer, "className", secondStyle);
+ final String splitterClass = CLASSNAME
+ + (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter"
+ : "-vsplitter");
+ final String firstContainerClass = CLASSNAME + "-first-container";
+ final String secondContainerClass = CLASSNAME + "-second-container";
+ final String lockedSuffix = locked ? "-locked" : "";
+
+ splitter.setClassName(splitterClass + lockedSuffix);
+ firstContainer.setClassName(firstContainerClass);
+ secondContainer.setClassName(secondContainerClass);
+
+ for (String styleName : componentStyleNames) {
+ splitter.addClassName(splitterClass + "-" + styleName
+ + lockedSuffix);
+ firstContainer.addClassName(firstContainerClass + "-" + styleName);
+ secondContainer
+ .addClassName(secondContainerClass + "-" + styleName);
+ }
}
public void setEnabled(boolean enabled) {
@@ -693,4 +756,14 @@ public class VAbstractSplitPanel extends ComplexPanel {
return enabled;
}
+ /**
+ * Ensures the panels are scrollable eg. after style name changes
+ */
+ void makeScrollable() {
+ if (touchScrollHandler == null) {
+ touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
+ }
+ touchScrollHandler.addElement(firstContainer);
+ touchScrollHandler.addElement(secondContainer);
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
index c45c26c4ac..c4a57f5c8b 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/table/VScrollTable.java
@@ -44,8 +44,6 @@ import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
-import com.google.gwt.event.dom.client.TouchStartEvent;
-import com.google.gwt.event.dom.client.TouchStartHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.user.client.Command;
@@ -236,6 +234,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
private boolean enableDebug = false;
+ private static final boolean hasNativeTouchScrolling = BrowserInfo.get()
+ .isTouchDevice()
+ && !BrowserInfo.get().requiresTouchScrollDelegate();
+
+ private Set<String> noncollapsibleColumns;
+
/**
* Represents a select range of rows
*/
@@ -268,6 +272,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
*
* @see java.lang.Object#toString()
*/
+
@Override
public String toString() {
return startRow.getKey() + "-" + length;
@@ -321,6 +326,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(true);
private KeyPressHandler navKeyPressHandler = new KeyPressHandler() {
+
public void onKeyPress(KeyPressEvent keyPressEvent) {
// This is used for Firefox only, since Firefox auto-repeat
// works correctly only if we use a key press handler, other
@@ -489,12 +495,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public VScrollTable() {
setMultiSelectMode(MULTISELECT_MODE_DEFAULT);
- scrollBodyPanel.setStyleName(CLASSNAME + "-body-wrapper");
+ scrollBodyPanel.addStyleName(CLASSNAME + "-body-wrapper");
scrollBodyPanel.addFocusHandler(this);
scrollBodyPanel.addBlurHandler(this);
scrollBodyPanel.addScrollHandler(this);
- scrollBodyPanel.setStyleName(CLASSNAME + "-body");
+ scrollBodyPanel.addStyleName(CLASSNAME + "-body");
/*
* Firefox auto-repeat works correctly only if we use a key press
@@ -509,14 +515,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
scrollBodyPanel.addKeyUpHandler(navKeyUpHandler);
scrollBodyPanel.sinkEvents(Event.TOUCHEVENTS);
- scrollBodyPanel.addDomHandler(new TouchStartHandler() {
- public void onTouchStart(TouchStartEvent event) {
- getTouchScrollDelegate().onTouchStart(event);
- }
- }, TouchStartEvent.getType());
scrollBodyPanel.sinkEvents(Event.ONCONTEXTMENU);
scrollBodyPanel.addDomHandler(new ContextMenuHandler() {
+
public void onContextMenu(ContextMenuEvent event) {
handleBodyContextMenu(event);
}
@@ -536,22 +538,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// Add a handler to clear saved context menu details when the menu
// closes. See #8526.
client.getContextMenu().addCloseHandler(new CloseHandler<PopupPanel>() {
+
public void onClose(CloseEvent<PopupPanel> event) {
contextMenu = null;
}
});
}
- protected TouchScrollDelegate getTouchScrollDelegate() {
- if (touchScrollDelegate == null) {
- touchScrollDelegate = new TouchScrollDelegate(
- scrollBodyPanel.getElement());
- touchScrollDelegate.setScrollHandler(this);
- }
- return touchScrollDelegate;
-
- }
-
private void handleBodyContextMenu(ContextMenuEvent event) {
if (enabled && bodyActionKeys != null) {
int left = Util.getTouchOrMouseClientX(event.getNativeEvent());
@@ -896,6 +889,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
updateHeader(uidl.getStringArrayAttribute("vcolorder"));
updateFooter(uidl.getStringArrayAttribute("vcolorder"));
+ if (uidl.hasVariable("noncollapsiblecolumns")) {
+ noncollapsibleColumns = uidl
+ .getStringArrayVariableAsSet("noncollapsiblecolumns");
+ }
}
private void updateCollapsedColumns(UIDL uidl) {
@@ -1848,12 +1845,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
isNewBody = false;
if (firstvisible > 0) {
- // FIXME #7607
- // Originally deferred due to Firefox oddities which should not
- // occur any more. Currently deferring breaks Webkit scrolling with
- // relative-height tables, but not deferring instead breaks tables
- // with explicit page length.
+ // Deferred due to some Firefox oddities
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
scrollBodyPanel
.setScrollPosition(measureRowHeightOffset(firstvisible));
@@ -1888,6 +1882,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
*/
scrollBody.reLayoutComponents();
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
}
@@ -2218,6 +2213,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
setWidth(tdWidth + "px");
} else {
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
int tdWidth = width
+ scrollBody.getCellExtraWidth();
@@ -2271,6 +2267,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/**
* Handle column reordering.
*/
+
@Override
public void onBrowserEvent(Event event) {
if (enabled && event != null) {
@@ -2814,6 +2811,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
final int newWidth = width;
Scheduler.get().scheduleDeferred(
new ScheduledCommand() {
+
public void execute() {
setColWidth(colIx, newWidth, true);
}
@@ -2841,6 +2839,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (refreshContentWidths) {
// Recalculate the column sizings if any column has changed
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+
public void execute() {
triggerLazyColumnAdjustment(true);
}
@@ -3029,6 +3028,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
String colKey;
private boolean collapsed;
+ private boolean noncollapsible = false;
private VScrollTableRow currentlyFocusedRow;
public VisibleColumnAction(String colKey) {
@@ -3040,6 +3040,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
@Override
public void execute() {
+ if (noncollapsible) {
+ return;
+ }
client.getContextMenu().hide();
// toggle selected column
if (collapsedColumns.contains(colKey)) {
@@ -3063,17 +3066,28 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
collapsed = b;
}
+ public void setNoncollapsible(boolean b) {
+ noncollapsible = b;
+ }
+
/**
* Override default method to distinguish on/off columns
*/
+
@Override
public String getHTML() {
final StringBuffer buf = new StringBuffer();
+ buf.append("<span class=\"");
if (collapsed) {
- buf.append("<span class=\"v-off\">");
+ buf.append("v-off");
} else {
- buf.append("<span class=\"v-on\">");
+ buf.append("v-on");
+ }
+ if (noncollapsible) {
+ buf.append(" v-disabled");
}
+ buf.append("\">");
+
buf.append(super.getHTML());
buf.append("</span>");
@@ -3085,6 +3099,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/*
* Returns columns as Action array for column select popup
*/
+
public Action[] getActions() {
Object[] cols;
if (columnReordering && columnOrder != null) {
@@ -3115,6 +3130,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (!c.isEnabled()) {
a.setCollapsed(true);
}
+ if (noncollapsibleColumns.contains(cid)) {
+ a.setNoncollapsible(true);
+ }
actions[i] = a;
}
return actions;
@@ -3200,6 +3218,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* The text in the footer
*/
public void setText(String footerText) {
+ if (footerText == null || footerText.equals("")) {
+ footerText = "&nbsp;";
+ }
+
DOM.setInnerHTML(captionContainer, footerText);
}
@@ -3295,6 +3317,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
setWidth(tdWidth + "px");
} else {
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
int borderWidths = 1;
int tdWidth = width
@@ -3541,6 +3564,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* com.google.gwt.user.client.ui.Panel#remove(com.google.gwt.user.client
* .ui.Widget)
*/
+
@Override
public boolean remove(Widget w) {
if (visibleCells.contains(w)) {
@@ -3557,6 +3581,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
*
* @see com.google.gwt.user.client.ui.HasWidgets#iterator()
*/
+
public Iterator<Widget> iterator() {
return visibleCells.iterator();
}
@@ -3835,7 +3860,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
DOM.appendChild(container, preSpacer);
DOM.appendChild(container, table);
DOM.appendChild(container, postSpacer);
- if (BrowserInfo.get().isTouchDevice()) {
+ if (BrowserInfo.get().requiresTouchScrollDelegate()) {
NodeList<Node> childNodes = container.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Element item = (Element) childNodes.getItem(i);
@@ -4388,7 +4413,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
private String[] actionKeys = null;
private final TableRowElement rowElement;
- private boolean mDown;
private int index;
private Event touchStart;
private static final String ROW_CLASSNAME_EVEN = CLASSNAME + "-row";
@@ -4396,8 +4420,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
+ "-row-odd";
private static final int TOUCH_CONTEXT_MENU_TIMEOUT = 500;
private Timer contextTouchTimeout;
+ private Timer dragTouchTimeout;
private int touchStartY;
private int touchStartX;
+ private boolean isDragging = false;
private VScrollTableRow(int rowKey) {
this.rowKey = rowKey;
@@ -4785,12 +4811,128 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
+ /**
+ * Special handler for touch devices that support native scrolling
+ *
+ * @return Whether the event was handled by this method.
+ */
+ private boolean handleTouchEvent(final Event event) {
+
+ boolean touchEventHandled = false;
+
+ if (enabled && hasNativeTouchScrolling) {
+ final Element targetTdOrTr = getEventTargetTdOrTr(event);
+ final int type = event.getTypeInt();
+
+ switch (type) {
+ case Event.ONTOUCHSTART:
+ touchEventHandled = true;
+ touchStart = event;
+ isDragging = false;
+ Touch touch = event.getChangedTouches().get(0);
+ // save position to fields, touches in events are same
+ // instance during the operation.
+ touchStartX = touch.getClientX();
+ touchStartY = touch.getClientY();
+
+ if (dragmode != 0) {
+ if (dragTouchTimeout == null) {
+ dragTouchTimeout = new Timer() {
+
+ @Override
+ public void run() {
+ if (touchStart != null) {
+ // Start a drag if a finger is held
+ // in place long enough, then moved
+ isDragging = true;
+ }
+ }
+ };
+ }
+ dragTouchTimeout.schedule(TOUCHSCROLL_TIMEOUT);
+ }
+
+ if (actionKeys != null) {
+ if (contextTouchTimeout == null) {
+ contextTouchTimeout = new Timer() {
+
+ @Override
+ public void run() {
+ if (touchStart != null) {
+ // Open the context menu if finger
+ // is held in place long enough.
+ showContextMenu(touchStart);
+ event.preventDefault();
+ touchStart = null;
+ }
+ }
+ };
+ }
+ contextTouchTimeout
+ .schedule(TOUCH_CONTEXT_MENU_TIMEOUT);
+ }
+ break;
+ case Event.ONTOUCHMOVE:
+ touchEventHandled = true;
+ if (isSignificantMove(event)) {
+ if (contextTouchTimeout != null) {
+ // Moved finger before the context menu timer
+ // expired, so let the browser handle this as a
+ // scroll.
+ contextTouchTimeout.cancel();
+ contextTouchTimeout = null;
+ }
+ if (!isDragging && dragTouchTimeout != null) {
+ // Moved finger before the drag timer expired,
+ // so let the browser handle this as a scroll.
+ dragTouchTimeout.cancel();
+ dragTouchTimeout = null;
+ }
+
+ if (dragmode != 0 && touchStart != null
+ && isDragging) {
+ event.preventDefault();
+ event.stopPropagation();
+ startRowDrag(touchStart, type, targetTdOrTr);
+ }
+ touchStart = null;
+ }
+ break;
+ case Event.ONTOUCHEND:
+ case Event.ONTOUCHCANCEL:
+ touchEventHandled = true;
+ if (contextTouchTimeout != null) {
+ contextTouchTimeout.cancel();
+ }
+ if (dragTouchTimeout != null) {
+ dragTouchTimeout.cancel();
+ }
+ if (touchStart != null) {
+ event.preventDefault();
+ event.stopPropagation();
+ if (!BrowserInfo.get().isAndroid()) {
+ Util.simulateClickFromTouchEvent(touchStart,
+ this);
+ }
+ touchStart = null;
+ }
+ isDragging = false;
+ break;
+ }
+ }
+ return touchEventHandled;
+ }
+
/*
* React on click that occur on content cells only
*/
+
@Override
public void onBrowserEvent(final Event event) {
- if (enabled) {
+
+ final boolean touchEventHandled = handleTouchEvent(event);
+
+ if (enabled && !touchEventHandled) {
final int type = event.getTypeInt();
final Element targetTdOrTr = getEventTargetTdOrTr(event);
if (type == Event.ONCONTEXTMENU) {
@@ -4823,7 +4965,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
break;
case Event.ONMOUSEUP:
if (targetCellOrRowFound) {
- mDown = false;
/*
* Queue here, send at the same time as the
* corresponding value change event - see #7127
@@ -4983,6 +5124,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
touchStart.preventDefault();
if (dragmode != 0 || actionKeys != null) {
new Timer() {
+
@Override
public void run() {
TouchScrollDelegate activeScrollDelegate = TouchScrollDelegate
@@ -5021,6 +5163,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (contextTouchTimeout == null
&& actionKeys != null) {
contextTouchTimeout = new Timer() {
+
@Override
public void run() {
if (touchStart != null) {
@@ -5066,9 +5209,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
break;
case Event.ONMOUSEOUT:
- if (targetCellOrRowFound) {
- mDown = false;
- }
break;
default:
break;
@@ -5098,7 +5238,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
protected void startRowDrag(Event event, final int type,
Element targetTdOrTr) {
- mDown = true;
VTransferable transferable = new VTransferable();
transferable.setDragSource(ConnectorMap.get(client)
.getConnector(VScrollTable.this));
@@ -5290,6 +5429,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
*
* @see com.vaadin.terminal.gwt.client.ui.IActionOwner#getActions ()
*/
+
public Action[] getActions() {
if (actionKeys == null) {
return new Action[] {};
@@ -5299,6 +5439,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
final String actionKey = actionKeys[i];
final TreeAction a = new TreeAction(this,
String.valueOf(rowKey), actionKey) {
+
@Override
public void execute() {
super.execute();
@@ -5586,6 +5727,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* column widths "optimally". Doing this lazily to avoid expensive
* calculation when resizing is not yet finished.
*/
+
@Override
public void run() {
if (scrollBody == null) {
@@ -5682,7 +5824,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (isDynamicHeight() && totalRows == pageLength) {
// fix body height (may vary if lazy loading is offhorizontal
// scrollbar appears/disappears)
- int bodyHeight = scrollBody.getRequiredHeight();
+ int bodyHeight = Util.getRequiredHeight(scrollBody);
boolean needsSpaceForHorizontalScrollbar = (availW < usedMinimumWidth);
if (needsSpaceForHorizontalScrollbar) {
bodyHeight += Util.getNativeScrollbarSize();
@@ -5695,6 +5837,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
scrollBody.reLayoutComponents();
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
}
@@ -5804,15 +5947,26 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
void updateHeight() {
setContainerHeight();
- updatePageLength();
-
+ if (initializedAndAttached) {
+ updatePageLength();
+ }
if (!rendering) {
// Webkit may sometimes get an odd rendering bug (white space
// between header and body), see bug #3875. Running
// overflow hack here to shake body element a bit.
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
+ // We must run the fix as a deferred command to prevent it from
+ // overwriting the scroll position with an outdated value, see
+ // #7607.
+ Scheduler.get().scheduleDeferred(new Command() {
+
+ public void execute() {
+ Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
+ }
+ });
}
+ triggerLazyColumnAdjustment(false);
+
/*
* setting height may affect wheter the component has scrollbars ->
* needs scrolling or not
@@ -5826,6 +5980,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* lost). Example ITabPanel just set contained components invisible and back
* when changing tabs.
*/
+
@Override
public void setVisible(boolean visible) {
if (isVisible() != visible) {
@@ -5833,6 +5988,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (initializedAndAttached) {
if (visible) {
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
scrollBodyPanel
.setScrollPosition(measureRowHeightOffset(firstRowInViewPort));
@@ -5866,6 +6022,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* This method has logic which rows needs to be requested from server when
* user scrolls
*/
+
public void onScroll(ScrollEvent event) {
scrollLeft = scrollBodyPanel.getElement().getScrollLeft();
scrollTop = scrollBodyPanel.getScrollPosition();
@@ -5894,6 +6051,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// correct
// value available soon.
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
onScroll(null);
}
@@ -5994,7 +6152,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return false;
}
- // @Override
+ //
// public int hashCode() {
// return overkey;
// }
@@ -6053,6 +6211,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
deEmphasis();
final TableDDDetails newDetails = dropDetails;
VAcceptCallback cb = new VAcceptCallback() {
+
public void accepted(VDragEvent event) {
if (newDetails.equals(dropDetails)) {
dragAccepted(event);
@@ -6459,6 +6618,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event
* .dom.client.FocusEvent)
*/
+
public void onFocus(FocusEvent event) {
if (isFocusable()) {
hasFocus = true;
@@ -6479,6 +6639,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event
* .dom.client.BlurEvent)
*/
+
public void onBlur(BlurEvent event) {
hasFocus = false;
navKeyDown = false;
@@ -6551,6 +6712,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
*
* @see com.vaadin.terminal.gwt.client.Focusable#focus()
*/
+
public void focus() {
if (isFocusable()) {
scrollBodyPanel.focus();
@@ -6594,6 +6756,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public void startScrollingVelocityTimer() {
if (scrollingVelocityTimer == null) {
scrollingVelocityTimer = new Timer() {
+
@Override
public void run() {
scrollingVelocity++;
@@ -6630,6 +6793,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public void lazyRevertFocusToRow(final VScrollTableRow currentlyFocusedRow) {
Scheduler.get().scheduleFinally(new ScheduledCommand() {
+
public void execute() {
if (currentlyFocusedRow != null) {
setRowFocus(currentlyFocusedRow);
diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java
index c97ede1252..aba5a41f9a 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheet.java
@@ -331,6 +331,11 @@ public class VTabsheet extends VTabsheetBase implements Focusable,
}
return width;
}
+
+ public Element getCloseButton() {
+ return closeButton;
+ }
+
}
static class TabBar extends ComplexPanel implements ClickHandler,
@@ -393,7 +398,14 @@ public class VTabsheet extends VTabsheetBase implements Focusable,
}
public void onClick(ClickEvent event) {
- Widget caption = (Widget) event.getSource();
+ TabCaption caption = (TabCaption) event.getSource();
+ Element targetElement = event.getNativeEvent().getEventTarget()
+ .cast();
+ // the tab should not be focused if the close button was clicked
+ if (targetElement == caption.getCloseButton()) {
+ return;
+ }
+
int index = getWidgetIndex(caption.getParent());
// IE needs explicit focus()
if (BrowserInfo.get().isIE()) {
@@ -1021,6 +1033,7 @@ public class VTabsheet extends VTabsheetBase implements Focusable,
final Style style = scroller.getStyle();
style.setProperty("whiteSpace", "normal");
Scheduler.get().scheduleDeferred(new Command() {
+
public void execute() {
style.setProperty("whiteSpace", "");
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java
index f2b37c3a1c..bd6cddb682 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/tabsheet/VTabsheetPanel.java
@@ -4,16 +4,12 @@
package com.vaadin.terminal.gwt.client.ui.tabsheet;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.event.dom.client.TouchStartEvent;
-import com.google.gwt.event.dom.client.TouchStartHandler;
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.ui.ComplexPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
+import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler;
/**
* A panel that displays all of its child widgets in a 'deck', where only one
@@ -27,38 +23,15 @@ import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate;
public class VTabsheetPanel extends ComplexPanel {
private Widget visibleWidget;
- private TouchScrollDelegate touchScrollDelegate;
+
+ private final TouchScrollHandler touchScrollHandler;
/**
* Creates an empty tabsheet panel.
*/
public VTabsheetPanel() {
setElement(DOM.createDiv());
- sinkEvents(Event.TOUCHEVENTS);
- addDomHandler(new TouchStartHandler() {
- public void onTouchStart(TouchStartEvent event) {
- /*
- * All container elements needs to be scrollable by one finger.
- * Update the scrollable element list of touch delegate on each
- * touch start.
- */
- NodeList<Node> childNodes = getElement().getChildNodes();
- Element[] elements = new Element[childNodes.getLength()];
- for (int i = 0; i < elements.length; i++) {
- elements[i] = (Element) childNodes.getItem(i);
- }
- getTouchScrollDelegate().setElements(elements);
- getTouchScrollDelegate().onTouchStart(event);
- }
- }, TouchStartEvent.getType());
- }
-
- protected TouchScrollDelegate getTouchScrollDelegate() {
- if (touchScrollDelegate == null) {
- touchScrollDelegate = new TouchScrollDelegate();
- }
- return touchScrollDelegate;
-
+ touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this);
}
/**
@@ -77,8 +50,8 @@ public class VTabsheetPanel extends ComplexPanel {
private Element createContainerElement() {
Element el = DOM.createDiv();
DOM.setStyleAttribute(el, "position", "absolute");
- DOM.setStyleAttribute(el, "overflow", "auto");
hide(el);
+ touchScrollHandler.addElement(el);
return el;
}
@@ -122,6 +95,7 @@ public class VTabsheetPanel extends ComplexPanel {
if (parent != null) {
DOM.removeChild(getElement(), parent);
}
+ touchScrollHandler.removeElement(parent);
}
return removed;
}
@@ -141,6 +115,8 @@ public class VTabsheetPanel extends ComplexPanel {
hide(DOM.getParent(visibleWidget.getElement()));
}
visibleWidget = newVisible;
+ touchScrollHandler.setElements(visibleWidget.getElement()
+ .getParentElement());
}
// Always ensure the selected tab is visible. If server prevents a tab
// change we might end up here with visibleWidget == newVisible but its
diff --git a/src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java b/src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java
index f7cd9d133e..9a8e0e9ce1 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/treetable/VTreeTable.java
@@ -379,26 +379,34 @@ public class VTreeTable extends VScrollTable {
rowsToDelete.add(row);
}
}
- RowCollapseAnimation anim = new RowCollapseAnimation(rowsToDelete) {
- @Override
- protected void onComplete() {
- super.onComplete();
- // Actually unlink the rows and update the cache after the
- // animation is done.
- unlinkAndReindexRows(firstIndex, rows);
- discardRowsOutsideCacheWindow();
- ensureCacheFilled();
- }
- };
- anim.run(150);
+ if (!rowsToDelete.isEmpty()) {
+ // #8810 Only animate if there's something to animate
+ RowCollapseAnimation anim = new RowCollapseAnimation(
+ rowsToDelete) {
+ @Override
+ protected void onComplete() {
+ super.onComplete();
+ // Actually unlink the rows and update the cache after
+ // the
+ // animation is done.
+ unlinkAndReindexRows(firstIndex, rows);
+ discardRowsOutsideCacheWindow();
+ ensureCacheFilled();
+ }
+ };
+ anim.run(150);
+ }
}
protected List<VScrollTableRow> insertRowsAnimated(UIDL rowData,
int firstIndex, int rows) {
List<VScrollTableRow> insertedRows = insertAndReindexRows(rowData,
firstIndex, rows);
- RowExpandAnimation anim = new RowExpandAnimation(insertedRows);
- anim.run(150);
+ if (!insertedRows.isEmpty()) {
+ // Only animate if there's something to animate (#8810)
+ RowExpandAnimation anim = new RowExpandAnimation(insertedRows);
+ anim.run(150);
+ }
return insertedRows;
}
@@ -521,6 +529,10 @@ public class VTreeTable extends VScrollTable {
private Element cloneTable;
private AnimationPreparator preparator;
+ /**
+ * @param rows
+ * List of rows to animate. Must not be empty.
+ */
public RowExpandAnimation(List<VScrollTableRow> rows) {
this.rows = rows;
buildAndInsertAnimatingDiv();
@@ -641,6 +653,10 @@ public class VTreeTable extends VScrollTable {
private final List<VScrollTableRow> rows;
+ /**
+ * @param rows
+ * List of rows to animate. Must not be empty.
+ */
public RowCollapseAnimation(List<VScrollTableRow> rows) {
super(rows);
this.rows = rows;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java
index d08387fc6d..8fd84a9ea6 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/window/VWindow.java
@@ -40,6 +40,7 @@ import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
import com.vaadin.terminal.gwt.client.ui.VOverlay;
+import com.vaadin.terminal.gwt.client.ui.notification.VNotification;
/**
* "Sub window" component.
@@ -264,8 +265,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
if (!orderingDefered) {
orderingDefered = true;
Scheduler.get().scheduleFinally(new Command() {
+
public void execute() {
doServerSideOrdering();
+ VNotification.bringNotificationsToFront();
}
});
}
@@ -275,6 +278,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
orderingDefered = false;
VWindow[] array = windowOrder.toArray(new VWindow[windowOrder.size()]);
Arrays.sort(array, new Comparator<VWindow>() {
+
public int compare(VWindow o1, VWindow o2) {
/*
* Order by modality, then by bringtofront sequence.