diff options
13 files changed, 242 insertions, 21 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 2e8387c5da..63dfde795b 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -65,6 +65,7 @@ import com.vaadin.client.ApplicationConfiguration.ErrorMessage; import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; import com.vaadin.client.communication.HasJavaScriptConnectorHelper; +import com.vaadin.client.communication.JavaScriptMethodInvocation; import com.vaadin.client.communication.JsonDecoder; import com.vaadin.client.communication.JsonEncoder; import com.vaadin.client.communication.RpcManager; @@ -2459,9 +2460,7 @@ public class ApplicationConnection { } private boolean isJavascriptRpc(MethodInvocation invocation) { - String connectorId = invocation.getConnectorId(); - ServerConnector connector = connectorMap.getConnector(connectorId); - return connector instanceof HasJavaScriptConnectorHelper; + return invocation instanceof JavaScriptMethodInvocation; } private boolean isLegacyVariableChange(MethodInvocation invocation) { @@ -3271,4 +3270,30 @@ public class ApplicationConnection { GwtEvent.Type<H> type, H handler) { return eventBus.addHandler(type, handler); } + + /** + * Calls {@link ComponentConnector#flush()} on the active connector. Does + * nothing if there is no active (focused) connector. + */ + public void flushActiveConnector() { + ComponentConnector activeConnector = getActiveConnector(); + if (activeConnector == null) { + return; + } + activeConnector.flush(); + } + + /** + * Gets the active connector for focused element in browser. + * + * @return Connector for focused element or null. + */ + private ComponentConnector getActiveConnector() { + Element focusedElement = Util.getFocusedElement(); + if (focusedElement == null) { + return null; + } + return Util.getConnectorForElement(this, getUIConnector().getWidget(), + focusedElement); + } } diff --git a/client/src/com/vaadin/client/ComponentConnector.java b/client/src/com/vaadin/client/ComponentConnector.java index 63e55153b6..db3cc25c56 100644 --- a/client/src/com/vaadin/client/ComponentConnector.java +++ b/client/src/com/vaadin/client/ComponentConnector.java @@ -127,4 +127,16 @@ public interface ComponentConnector extends ServerConnector { */ public TooltipInfo getTooltipInfo(Element element); + /** + * Called for the active (focused) connector when a situation occurs that + * the focused connector might have buffered changes which need to be + * processed before other activity takes place. + * <p> + * This is currently called when the user changes the fragment using the + * back/forward button in the browser and allows the focused field to submit + * its value to the server before the fragment change event takes place. + * </p> + */ + public void flush(); + } diff --git a/client/src/com/vaadin/client/JavaScriptConnectorHelper.java b/client/src/com/vaadin/client/JavaScriptConnectorHelper.java index b275cd0a68..73752e4ddb 100644 --- a/client/src/com/vaadin/client/JavaScriptConnectorHelper.java +++ b/client/src/com/vaadin/client/JavaScriptConnectorHelper.java @@ -27,6 +27,7 @@ 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.client.communication.JavaScriptMethodInvocation; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; import com.vaadin.shared.JavaScriptConnectorState; @@ -258,8 +259,8 @@ public class JavaScriptConnectorHelper { parameters[i] = argumentsArray.get(i); } connector.getConnection().addMethodInvocationToQueue( - new MethodInvocation(connector.getConnectorId(), iface, method, - parameters), false, false); + new JavaScriptMethodInvocation(connector.getConnectorId(), + iface, method, parameters), false, false); } private String findWildcardInterface(String method) { @@ -286,7 +287,7 @@ public class JavaScriptConnectorHelper { } private void fireCallback(String name, JsArray<JavaScriptObject> arguments) { - MethodInvocation invocation = new MethodInvocation( + MethodInvocation invocation = new JavaScriptMethodInvocation( connector.getConnectorId(), "com.vaadin.ui.JavaScript$JavaScriptCallbackRpc", "call", new Object[] { name, new JSONArray(arguments) }); diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java index 0df8bfb90f..3d6f64d4d5 100644 --- a/client/src/com/vaadin/client/Util.java +++ b/client/src/com/vaadin/client/Util.java @@ -1059,11 +1059,11 @@ public class Util { } /** - * Gets the currently focused element for Internet Explorer. + * Gets the currently focused element. * - * @return The currently focused element + * @return The active element or null if no active element could be found. */ - public native static Element getIEFocusedElement() + public native static Element getFocusedElement() /*-{ if ($wnd.document.activeElement) { return $wnd.document.activeElement; @@ -1072,6 +1072,17 @@ public class Util { return null; }-*/ ; + + /** + * Gets the currently focused element for Internet Explorer. + * + * @return The currently focused element + * @deprecated Use #getFocusedElement instead + */ + @Deprecated + public static Element getIEFocusedElement() { + return getFocusedElement(); + } /** * Kind of stronger version of isAttached(). In addition to std isAttached, diff --git a/client/src/com/vaadin/client/communication/JavaScriptMethodInvocation.java b/client/src/com/vaadin/client/communication/JavaScriptMethodInvocation.java new file mode 100644 index 0000000000..00f563e333 --- /dev/null +++ b/client/src/com/vaadin/client/communication/JavaScriptMethodInvocation.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.client.communication; + +import com.vaadin.shared.communication.MethodInvocation; + +/** + * A {@link MethodInvocation} that originates from JavaScript. This means that + * there might not be any type information available on the client. + * + * @author Vaadin Ltd + * @since 7.0.0 + */ +public class JavaScriptMethodInvocation extends MethodInvocation { + + public JavaScriptMethodInvocation(String connectorId, String interfaceName, + String methodName, Object[] parameters) { + super(connectorId, interfaceName, methodName, parameters); + } +} diff --git a/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java b/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java index 2550fce208..078e19f73b 100644 --- a/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java +++ b/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java @@ -24,8 +24,8 @@ import com.google.gwt.core.client.JsArray; import com.google.gwt.json.client.JSONArray; import com.vaadin.client.ServerConnector; import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.communication.JavaScriptMethodInvocation; import com.vaadin.client.extensions.AbstractExtensionConnector; -import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc; import com.vaadin.shared.extension.javascriptmanager.JavaScriptManagerState; import com.vaadin.shared.ui.Connect; @@ -123,7 +123,7 @@ public class JavaScriptManagerConnector extends AbstractExtensionConnector { * because of the JSONArray parameter */ getConnection().addMethodInvocationToQueue( - new MethodInvocation(getConnectorId(), + new JavaScriptMethodInvocation(getConnectorId(), "com.vaadin.ui.JavaScript$JavaScriptCallbackRpc", "call", parameters), false, false); } diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java index f8088d63a2..2c599743e4 100644 --- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java +++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java @@ -426,4 +426,13 @@ public abstract class AbstractComponentConnector extends AbstractConnector protected String getIcon() { return getResourceUrl(ComponentConstants.ICON_RESOURCE); } + + /* + * (non-Javadoc) + * + * @see com.vaadin.client.ComponentConnector#flush() + */ + public void flush() { + // No generic implementation. Override if needed + } } diff --git a/client/src/com/vaadin/client/ui/VUI.java b/client/src/com/vaadin/client/ui/VUI.java index cbfbda813e..a21397c060 100644 --- a/client/src/com/vaadin/client/ui/VUI.java +++ b/client/src/com/vaadin/client/ui/VUI.java @@ -129,8 +129,10 @@ public class VUI extends SimplePanel implements ResizeHandler, String newFragment = event.getValue(); // Send the location to the server if the fragment has changed + // and flush active connectors in UI. if (!newFragment.equals(currentFragment) && connection != null) { currentFragment = newFragment; + connection.flushActiveConnector(); connection.updateVariable(id, UIConstants.LOCATION_VARIABLE, Window.Location.getHref(), true); } diff --git a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java index afcf479499..8875fc421b 100644 --- a/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java +++ b/client/src/com/vaadin/client/ui/richtextarea/RichTextAreaConnector.java @@ -75,12 +75,17 @@ public class RichTextAreaConnector extends AbstractFieldConnector implements @Override public void onBeforeShortcutAction(Event e) { - getWidget().synchronizeContentToServer(); + flush(); } @Override public VRichTextArea getWidget() { return (VRichTextArea) super.getWidget(); + } + + @Override + public void flush() { + getWidget().synchronizeContentToServer(); }; } diff --git a/client/src/com/vaadin/client/ui/textfield/TextFieldConnector.java b/client/src/com/vaadin/client/ui/textfield/TextFieldConnector.java index c653b06cf9..bedcd5f936 100644 --- a/client/src/com/vaadin/client/ui/textfield/TextFieldConnector.java +++ b/client/src/com/vaadin/client/ui/textfield/TextFieldConnector.java @@ -114,6 +114,11 @@ public class TextFieldConnector extends AbstractFieldConnector implements @Override public void onBeforeShortcutAction(Event e) { + flush(); + } + + @Override + public void flush() { getWidget().valueChange(false); } diff --git a/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.html b/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.html index 67964d9fb2..6975ef84d4 100644 --- a/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.html +++ b/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.html @@ -19,7 +19,7 @@ <tr> <td>assertText</td> <td>label</td> - <td>no ConversionException</td> + <td>no Exception</td> </tr> <tr> <td>assertElementPresent</td> @@ -34,7 +34,7 @@ <tr> <td>assertText</td> <td>label</td> - <td>no ConversionException</td> + <td>no Exception</td> </tr> <tr> <td>assertElementNotPresent</td> @@ -49,7 +49,7 @@ <tr> <td>assertText</td> <td>label</td> - <td>ConversionException caught</td> + <td>Exception caught</td> </tr> <tr> <td>assertElementPresent</td> @@ -64,7 +64,7 @@ <tr> <td>assertText</td> <td>label</td> - <td>no ConversionException</td> + <td>no Exception</td> </tr> <tr> <td>assertElementNotPresent</td> @@ -79,7 +79,7 @@ <tr> <td>assertText</td> <td>label</td> - <td>ConversionException caught</td> + <td>Exception caught</td> </tr> <tr> <td>assertElementPresent</td> diff --git a/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.java b/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.java index dbdd810440..f6eb893528 100644 --- a/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.java +++ b/uitest/src/com/vaadin/tests/components/table/SetDataSourceWithPropertyIds.java @@ -4,8 +4,8 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import com.vaadin.data.Buffered.SourceException; import com.vaadin.data.util.BeanItemContainer; -import com.vaadin.data.util.converter.Converter.ConversionException; import com.vaadin.server.VaadinRequest; import com.vaadin.shared.ui.MarginInfo; import com.vaadin.tests.components.AbstractTestUI; @@ -70,12 +70,12 @@ public class SetDataSourceWithPropertyIds extends AbstractTestUI { try { table.setContainerDataSource(jobContainer); table.setVisibleColumns(new String[] { "jobId" }); - label.setValue("no ConversionException"); - } catch (ConversionException e) { + label.setValue("no Exception"); + } catch (SourceException e) { ArrayList<String> propertyIds = new ArrayList<String>(); propertyIds.add("jobId"); table.setContainerDataSource(jobContainer, propertyIds); - label.setValue("ConversionException caught"); + label.setValue("Exception caught"); } } diff --git a/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java b/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java new file mode 100644 index 0000000000..d5bac0d509 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java @@ -0,0 +1,117 @@ +package com.vaadin.tests.components.uitest; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.server.Page.UriFragmentChangedEvent; +import com.vaadin.server.Page.UriFragmentChangedListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; +import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; + +public class BackButtonTest extends AbstractTestUI { + + private VerticalLayout layout; + + private String value = "Hello"; + private Page1 p1; + private Page2 p2; + + @Override + public void setup(VaadinRequest request) { + getPage().setUriFragment("page1"); + + layout = new VerticalLayout(); + addComponent(layout); + + p1 = new Page1(); + addComponent(p1); + + p2 = new Page2(); + getPage().addUriFragmentChangedListener( + new UriFragmentChangedListener() { + + @Override + public void uriFragmentChanged(UriFragmentChangedEvent event) { + String f = event.getUriFragment(); + if ("page2".equals(f)) { + showPage2(); + } + + if ("page1".equals(f)) { + showPage1(); + } + } + }); + } + + class Page1 extends VerticalLayout { + Label l = new Label(); + + public Page1() { + setSizeFull(); + l.setCaption("Data from Page 1 : " + value); + addComponent(l); + + Button b = new Button("Go to Page 2", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + l.setCaption("Data from Page 1 : " + value); + getPage().setUriFragment("page2"); + } + }); + addComponent(b); + } + } + + private void showPage2() { + removeComponent(p1); + p2.f.setValue(""); + addComponent(p2); + } + + private void showPage1() { + removeComponent(p2); + addComponent(p1); + } + + class Page2 extends VerticalLayout { + private final TextField f = new TextField(); + + public Page2() { + setSizeFull(); + + addComponent(f); + f.addValueChangeListener(new ValueChangeListener() { + public void valueChange(ValueChangeEvent event) { + value = f.getValue(); + p1.l.setCaption("Data from Page 2 : " + value); + } + }); + + Button b = new Button("Go Back", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + getPage().setUriFragment("page1"); + } + }); + addComponent(b); + addComponent(new Label( + "Go back with the back button without creating a blur event on the text field. Text should transfer to page1 label.")); + } + + } + + @Override + protected Integer getTicketNumber() { + return 9949; + } + + @Override + protected String getTestDescription() { + // TODO Auto-generated method stub + return null; + } + +} |