From 2bc4f17916e919d7b92dcf03877c7bf2ff0f51c8 Mon Sep 17 00:00:00 2001 From: Matti Hosio Date: Fri, 9 Jan 2015 16:20:38 +0200 Subject: Make responsive work with setTheme (#15281) The size break points are now parsed again when the theme is changed Change-Id: Ic1583926942966fda29025e4cf2d7298691189f9 --- .../extensions/SetThemeAndResponsiveLayout.java | 59 +++++++++++++++++ .../SetThemeAndResponsiveLayoutTest.java | 76 ++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayout.java create mode 100644 uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayoutTest.java (limited to 'uitest/src') diff --git a/uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayout.java b/uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayout.java new file mode 100644 index 0000000000..f3df1a1176 --- /dev/null +++ b/uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayout.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 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.tests.extensions; + +import com.vaadin.server.Responsive; +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.CssLayout; +import com.vaadin.ui.Label; + +public class SetThemeAndResponsiveLayout extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + getLayout().setSizeFull(); + CssLayout responsiveLayout = new CssLayout(); + responsiveLayout.addStyleName("width-and-height"); + responsiveLayout.setSizeFull(); + setContent(responsiveLayout); + responsiveLayout + .addComponent(new Label( + "First set the theme using the button and then resize the browser window in both dimensions to see the background color change.")); + Button setThemeButton = new Button("Set theme"); + setThemeButton.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + setTheme("tests-responsive"); + } + }); + responsiveLayout.addComponent(setThemeButton); + Responsive.makeResponsive(responsiveLayout); + } + + @Override + protected String getTestDescription() { + return "This test verifies that responsive works also when theme is set using setTheme method"; + }; + + @Override + protected Integer getTicketNumber() { + return 15281; + }; + +} diff --git a/uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayoutTest.java b/uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayoutTest.java new file mode 100644 index 0000000000..8a1fbde245 --- /dev/null +++ b/uitest/src/com/vaadin/tests/extensions/SetThemeAndResponsiveLayoutTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2014 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.tests.extensions; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.CssLayoutElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class SetThemeAndResponsiveLayoutTest extends MultiBrowserTest { + + @Before + public void setUp() throws Exception { + // We need this in order to ensure that the initial width-range is + // width: 600px- and height: 500px- + testBench().resizeViewPortTo(1024, 768); + } + + @Override + public List getBrowsersToTest() { + // Seems like stylesheet onload is not fired on PhantomJS + // https://github.com/ariya/phantomjs/issues/12332 + return super.getBrowsersExcludingPhantomJS(); + } + + @Test + public void testWidthAndHeightRanges() throws Exception { + openTestURL(); + // IE sometimes has trouble waiting long enough. + new WebDriverWait(getDriver(), 30).until(ExpectedConditions + .presenceOfElementLocated(By + .cssSelector(".v-csslayout-width-and-height"))); + // set the theme programmatically + $(ButtonElement.class).caption("Set theme").first().click(); + new WebDriverWait(getDriver(), 30).until(ExpectedConditions + .presenceOfElementLocated(By.xpath("//div[@width-range]"))); + + // Verify both width-range and height-range. + assertEquals("600px-", + $(CssLayoutElement.class).first().getAttribute("width-range")); + assertEquals("500px-", + $(CssLayoutElement.class).first().getAttribute("height-range")); + + // Resize + testBench().resizeViewPortTo(550, 450); + + // Verify updated width-range and height-range. + assertEquals("0-599px", + $(CssLayoutElement.class).first().getAttribute("width-range")); + assertEquals("0-499px", + $(CssLayoutElement.class).first().getAttribute("height-range")); + } +} -- cgit v1.2.3 From e20f6fd54ae4b350ea654807b98fe442e546d1a8 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Sat, 10 Jan 2015 22:19:36 +0200 Subject: Include UI class @JavaScript and @StyleSheet in bootstrap html (#9045) Change-Id: I9d4243fa6f91ba5bc3449d0a3ec24f209e6360e6 --- .../VAADIN/themes/tests-valo/uiDependency.css | 0 .../vaadin/client/ApplicationConfiguration.java | 11 +- .../com/vaadin/client/ApplicationConnection.java | 128 ++++++--------------- .../communication/AtmospherePushConnection.java | 3 +- .../com/vaadin/client/communication/Heartbeat.java | 3 +- .../extensions/BrowserWindowOpenerConnector.java | 5 +- .../ApplicationConnectionURLGenerationTest.java | 10 +- server/src/com/vaadin/server/BootstrapHandler.java | 106 ++++++++++++++++- .../communication/PortletBootstrapHandler.java | 16 ++- .../com/vaadin/shared/ApplicationConstants.java | 6 +- .../src/com/vaadin/shared/VaadinUriResolver.java | 95 +++++++++++++++ shared/src/com/vaadin/shared/util/SharedUtil.java | 41 +++++++ .../tests/components/ui/UiDependenciesInHtml.java | 38 ++++++ .../components/ui/UiDependenciesInHtmlTest.java | 37 ++++++ .../com/vaadin/tests/components/ui/uiDependency.js | 24 ++++ 15 files changed, 398 insertions(+), 125 deletions(-) create mode 100644 WebContent/VAADIN/themes/tests-valo/uiDependency.css create mode 100644 shared/src/com/vaadin/shared/VaadinUriResolver.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtml.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtmlTest.java create mode 100644 uitest/src/com/vaadin/tests/components/ui/uiDependency.js (limited to 'uitest/src') diff --git a/WebContent/VAADIN/themes/tests-valo/uiDependency.css b/WebContent/VAADIN/themes/tests-valo/uiDependency.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index 0ef37df130..5eeeabe743 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -276,8 +276,7 @@ public class ApplicationConfiguration implements EntryPoint { * false if the path info goes after the service URL */ public boolean useServiceUrlPathParam() { - return getJsoConfiguration(id).getConfigBoolean( - ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER) == Boolean.TRUE; + return getServiceUrlParameterName() != null; } /** @@ -289,12 +288,8 @@ public class ApplicationConfiguration implements EntryPoint { * @return The parameter name, by default v-resourcePath */ public String getServiceUrlParameterName() { - String prefix = getJsoConfiguration(id).getConfigString( - ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE); - if (prefix == null) { - prefix = ""; - } - return prefix + ApplicationConstants.V_RESOURCE_PATH; + return getJsoConfiguration(id).getConfigString( + ApplicationConstants.SERVICE_URL_PARAMETER_NAME); } public String getRootPanelId() { diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index cd69f6c186..3431f06431 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -99,12 +99,14 @@ import com.vaadin.client.ui.window.WindowConnector; import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.JsonConstants; +import com.vaadin.shared.VaadinUriResolver; import com.vaadin.shared.Version; import com.vaadin.shared.communication.LegacyChangeVariablesInvocation; import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.communication.SharedState; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; +import com.vaadin.shared.util.SharedUtil; /** * This is the client side communication "engine", managing client-server @@ -472,6 +474,33 @@ public class ApplicationConnection implements HasHandlers { private boolean tooltipInitialized = false; + private final VaadinUriResolver uriResolver = new VaadinUriResolver() { + @Override + protected String getVaadinDirUrl() { + return getConfiguration().getVaadinDirUrl(); + } + + @Override + protected String getServiceUrlParameterName() { + return getConfiguration().getServiceUrlParameterName(); + } + + @Override + protected String getServiceUrl() { + return getConfiguration().getServiceUrl(); + } + + @Override + protected String getThemeUri() { + return ApplicationConnection.this.getThemeUri(); + } + + @Override + protected String encodeQueryStringParameterValue(String queryString) { + return URL.encodeQueryString(queryString); + } + }; + public static class MultiStepDuration extends Duration { private int previousStep = elapsedMillis(); @@ -823,10 +852,10 @@ public class ApplicationConnection implements HasHandlers { + ApplicationConstants.UIDL_PATH + '/'); if (extraParams != null && extraParams.length() > 0) { - uri = addGetParameters(uri, extraParams); + uri = SharedUtil.addGetParameters(uri, extraParams); } - uri = addGetParameters(uri, UIConstants.UI_ID_PARAMETER + "=" - + configuration.getUIId()); + uri = SharedUtil.addGetParameters(uri, UIConstants.UI_ID_PARAMETER + + "=" + configuration.getUIId()); doUidlRequest(uri, payload); @@ -3185,67 +3214,7 @@ public class ApplicationConnection implements HasHandlers { * @return translated URI ready for browser */ public String translateVaadinUri(String uidlUri) { - if (uidlUri == null) { - return null; - } - if (uidlUri.startsWith("theme://")) { - final String themeUri = getThemeUri(); - if (themeUri == null) { - VConsole.error("Theme not set: ThemeResource will not be found. (" - + uidlUri + ")"); - } - uidlUri = themeUri + uidlUri.substring(7); - } - - if (uidlUri.startsWith(ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX)) { - // getAppUri *should* always end with / - // substring *should* always start with / (published:///foo.bar - // without published://) - uidlUri = ApplicationConstants.APP_PROTOCOL_PREFIX - + ApplicationConstants.PUBLISHED_FILE_PATH - + uidlUri - .substring(ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX - .length()); - // Let translation of app:// urls take care of the rest - } - if (uidlUri.startsWith(ApplicationConstants.APP_PROTOCOL_PREFIX)) { - String relativeUrl = uidlUri - .substring(ApplicationConstants.APP_PROTOCOL_PREFIX - .length()); - ApplicationConfiguration conf = getConfiguration(); - String serviceUrl = conf.getServiceUrl(); - if (conf.useServiceUrlPathParam()) { - // Should put path in v-resourcePath parameter and append query - // params to base portlet url - String[] parts = relativeUrl.split("\\?", 2); - String path = parts[0]; - - // If there's a "?" followed by something, append it as a query - // string to the base URL - if (parts.length > 1) { - String appUrlParams = parts[1]; - serviceUrl = addGetParameters(serviceUrl, appUrlParams); - } - if (!path.startsWith("/")) { - path = '/' + path; - } - String pathParam = conf.getServiceUrlParameterName() + "=" - + URL.encodeQueryString(path); - serviceUrl = addGetParameters(serviceUrl, pathParam); - uidlUri = serviceUrl; - } else { - uidlUri = serviceUrl + relativeUrl; - } - } - if (uidlUri.startsWith(ApplicationConstants.VAADIN_PROTOCOL_PREFIX)) { - final String vaadinUri = configuration.getVaadinDirUrl(); - String relativeUrl = uidlUri - .substring(ApplicationConstants.VAADIN_PROTOCOL_PREFIX - .length()); - uidlUri = vaadinUri + relativeUrl; - } - - return uidlUri; + return uriResolver.resolveVaadinUri(uidlUri); } /** @@ -3362,35 +3331,12 @@ public class ApplicationConnection implements HasHandlers { * One or more parameters in the format "a=b" or "c=d&e=f". An * empty string is allowed but will not modify the url. * @return The modified URI with the get parameters in extraParams added. + * @deprecated Use {@link SharedUtil#addGetParameters(String,String)} + * instead */ + @Deprecated public static String addGetParameters(String uri, String extraParams) { - if (extraParams == null || extraParams.length() == 0) { - return uri; - } - // RFC 3986: The query component is indicated by the first question - // mark ("?") character and terminated by a number sign ("#") character - // or by the end of the URI. - String fragment = null; - int hashPosition = uri.indexOf('#'); - if (hashPosition != -1) { - // Fragment including "#" - fragment = uri.substring(hashPosition); - // The full uri before the fragment - uri = uri.substring(0, hashPosition); - } - - if (uri.contains("?")) { - uri += "&"; - } else { - uri += "?"; - } - uri += extraParams; - - if (fragment != null) { - uri += fragment; - } - - return uri; + return SharedUtil.addGetParameters(uri, extraParams); } ConnectorMap getConnectorMap() { diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index d10449ccaa..a2346db186 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -35,6 +35,7 @@ import com.vaadin.shared.Version; import com.vaadin.shared.communication.PushConstants; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIState.PushConfigurationState; +import com.vaadin.shared.util.SharedUtil; /** * The default {@link PushConnection} implementation that uses Atmosphere for @@ -185,7 +186,7 @@ public class AtmospherePushConnection implements PushConnection { } // uri is needed to identify the right connection when closing - uri = ApplicationConnection.addGetParameters(baseUrl, extraParams); + uri = SharedUtil.addGetParameters(baseUrl, extraParams); VConsole.log("Establishing push connection"); socket = doConnect(uri, getConfig()); diff --git a/client/src/com/vaadin/client/communication/Heartbeat.java b/client/src/com/vaadin/client/communication/Heartbeat.java index b9493d4520..5d15e5585f 100644 --- a/client/src/com/vaadin/client/communication/Heartbeat.java +++ b/client/src/com/vaadin/client/communication/Heartbeat.java @@ -28,6 +28,7 @@ import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; import com.vaadin.client.ApplicationConnection.ConnectionStatusEvent; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.ui.ui.UIConstants; +import com.vaadin.shared.util.SharedUtil; /** * Handles sending of heartbeats to the server and reacting to the response @@ -63,7 +64,7 @@ public class Heartbeat { setInterval(connection.getConfiguration().getHeartbeatInterval()); - uri = ApplicationConnection.addGetParameters(connection + uri = SharedUtil.addGetParameters(connection .translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX + ApplicationConstants.HEARTBEAT_PATH + '/'), UIConstants.UI_ID_PARAMETER + "=" diff --git a/client/src/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java b/client/src/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java index 58457c1b7b..11e3e80a14 100644 --- a/client/src/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java +++ b/client/src/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java @@ -23,12 +23,12 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.http.client.URL; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Widget; -import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ServerConnector; import com.vaadin.server.BrowserWindowOpener; import com.vaadin.shared.ui.BrowserWindowOpenerState; import com.vaadin.shared.ui.Connect; +import com.vaadin.shared.util.SharedUtil; /** * Client-side code for {@link BrowserWindowOpener} @@ -81,8 +81,7 @@ public class BrowserWindowOpenerConnector extends AbstractExtensionConnector } } - url = ApplicationConnection - .addGetParameters(url, params.toString()); + url = SharedUtil.addGetParameters(url, params.toString()); } if (getState().uriFragment != null) { diff --git a/client/tests/src/com/vaadin/client/ApplicationConnectionURLGenerationTest.java b/client/tests/src/com/vaadin/client/ApplicationConnectionURLGenerationTest.java index 36baa163cb..f529ba0886 100644 --- a/client/tests/src/com/vaadin/client/ApplicationConnectionURLGenerationTest.java +++ b/client/tests/src/com/vaadin/client/ApplicationConnectionURLGenerationTest.java @@ -4,6 +4,8 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; +import com.vaadin.shared.util.SharedUtil; + public class ApplicationConnectionURLGenerationTest { private static final String[] URIS = new String[] { @@ -51,23 +53,23 @@ public class ApplicationConnectionURLGenerationTest { for (int i = 0; i < URIS.length; i++) { // Adding nothing assertEquals(URIS[i], - ApplicationConnection.addGetParameters(URIS[i], "")); + SharedUtil.addGetParameters(URIS[i], "")); // Adding a=b&c=d assertEquals(URIS_WITH_ABCD_PARAM[i], - ApplicationConnection.addGetParameters(URIS[i], "a=b&c=d")); + SharedUtil.addGetParameters(URIS[i], "a=b&c=d")); // Fragments if (URIS_WITH_ABCD_PARAM_AND_FRAGMENT[i].length() > 0) { assertEquals( URIS_WITH_ABCD_PARAM_AND_FRAGMENT[i], - ApplicationConnection.addGetParameters(URIS[i] + SharedUtil.addGetParameters(URIS[i] + "#fragment", "a=b&c=d")); // Empty fragment assertEquals(URIS_WITH_ABCD_PARAM_AND_FRAGMENT[i].replace( "#fragment", "#"), - ApplicationConnection.addGetParameters(URIS[i] + "#", + SharedUtil.addGetParameters(URIS[i] + "#", "a=b&c=d")); } } diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index c45e2b70e0..e74f6d7c45 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -37,10 +37,14 @@ import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import org.jsoup.parser.Tag; +import com.google.gwt.thirdparty.guava.common.net.UrlEscapers; +import com.vaadin.annotations.JavaScript; +import com.vaadin.annotations.StyleSheet; import com.vaadin.annotations.Viewport; import com.vaadin.annotations.ViewportGeneratorClass; import com.vaadin.server.communication.AtmospherePushConnection; import com.vaadin.shared.ApplicationConstants; +import com.vaadin.shared.VaadinUriResolver; import com.vaadin.shared.Version; import com.vaadin.shared.communication.PushMode; import com.vaadin.ui.UI; @@ -76,6 +80,8 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { private String themeName; private String appId; private PushMode pushMode; + private JsonObject applicationParameters; + private VaadinUriResolver uriResolver; public BootstrapContext(VaadinResponse response, BootstrapFragmentResponse bootstrapResponse) { @@ -149,6 +155,71 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { return bootstrapResponse; } + public JsonObject getApplicationParameters() { + if (applicationParameters == null) { + applicationParameters = BootstrapHandler.this + .getApplicationParameters(this); + } + + return applicationParameters; + } + + public VaadinUriResolver getUriResolver() { + if (uriResolver == null) { + uriResolver = new BootstrapUriResolver(this); + } + + return uriResolver; + } + } + + private class BootstrapUriResolver extends VaadinUriResolver { + private final BootstrapContext context; + + public BootstrapUriResolver(BootstrapContext bootstrapContext) { + context = bootstrapContext; + } + + @Override + protected String getVaadinDirUrl() { + return context.getApplicationParameters().getString( + ApplicationConstants.VAADIN_DIR_URL); + } + + @Override + protected String getThemeUri() { + return getVaadinDirUrl() + "themes/" + context.getThemeName(); + } + + @Override + protected String getServiceUrlParameterName() { + return getConfigOrNull(ApplicationConstants.SERVICE_URL_PARAMETER_NAME); + } + + @Override + protected String getServiceUrl() { + String serviceUrl = getConfigOrNull(ApplicationConstants.SERVICE_URL); + if (serviceUrl == null) { + return "./"; + } else if (!serviceUrl.endsWith("/")) { + serviceUrl += "/"; + } + return serviceUrl; + } + + private String getConfigOrNull(String name) { + JsonObject parameters = context.getApplicationParameters(); + if (parameters.hasKey(name)) { + return parameters.getString(name); + } else { + return null; + } + } + + @Override + protected String encodeQueryStringParameterValue(String queryString) { + return UrlEscapers.urlFormParameterEscaper().escape(queryString); + } } @Override @@ -345,11 +416,41 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { .attr("href", themeUri + "/favicon.ico"); } + JavaScript javaScript = uiClass.getAnnotation(JavaScript.class); + if (javaScript != null) { + String[] resources = javaScript.value(); + for (String resource : resources) { + String url = registerDependency(context, uiClass, resource); + head.appendElement("script").attr("type", "text/javascript") + .attr("src", url); + } + } + + StyleSheet styleSheet = uiClass.getAnnotation(StyleSheet.class); + if (styleSheet != null) { + String[] resources = styleSheet.value(); + for (String resource : resources) { + String url = registerDependency(context, uiClass, resource); + head.appendElement("link").attr("rel", "stylesheet") + .attr("type", "text/css").attr("href", url); + } + } + Element body = document.body(); body.attr("scroll", "auto"); body.addClass(ApplicationConstants.GENERATED_BODY_CLASSNAME); } + private String registerDependency(BootstrapContext context, + Class uiClass, String resource) { + String url = context.getSession().getCommunicationManager() + .registerDependency(resource, uiClass); + + url = context.getUriResolver().resolveVaadinUri(url); + + return url; + } + protected String getMainDivStyle(BootstrapContext context) { return null; } @@ -457,7 +558,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { protected void appendMainScriptTagContents(BootstrapContext context, StringBuilder builder) throws IOException { - JsonObject appConfig = getApplicationParameters(context); + JsonObject appConfig = context.getApplicationParameters(); boolean isDebug = !context.getSession().getConfiguration() .isProductionMode(); @@ -490,8 +591,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { } } - protected JsonObject getApplicationParameters(BootstrapContext context) - throws PaintException { + protected JsonObject getApplicationParameters(BootstrapContext context) { VaadinRequest request = context.getRequest(); VaadinSession session = context.getSession(); VaadinService vaadinService = request.getService(); diff --git a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java index 1d1a300cd1..289309b631 100644 --- a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java +++ b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java @@ -26,7 +26,6 @@ import javax.portlet.RenderResponse; import javax.portlet.ResourceURL; import com.vaadin.server.BootstrapHandler; -import com.vaadin.server.PaintException; import com.vaadin.server.VaadinPortlet; import com.vaadin.server.VaadinPortlet.VaadinLiferayRequest; import com.vaadin.server.VaadinPortletRequest; @@ -36,6 +35,7 @@ import com.vaadin.server.VaadinResponse; import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinSession; import com.vaadin.shared.ApplicationConstants; + import elemental.json.JsonObject; public class PortletBootstrapHandler extends BootstrapHandler { @@ -92,8 +92,7 @@ public class PortletBootstrapHandler extends BootstrapHandler { } @Override - protected JsonObject getApplicationParameters(BootstrapContext context) - throws PaintException { + protected JsonObject getApplicationParameters(BootstrapContext context) { JsonObject parameters = super.getApplicationParameters(context); VaadinPortletResponse response = (VaadinPortletResponse) context .getResponse(); @@ -105,17 +104,16 @@ public class PortletBootstrapHandler extends BootstrapHandler { resourceURL.setResourceID("v-browserDetails"); parameters.put("browserDetailsUrl", resourceURL.toString()); - // Always send path info as a query parameter - parameters - .put(ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER, true); + String serviceUrlParameterName = ApplicationConstants.V_RESOURCE_PATH; // If we are running in Liferay then we need to prefix all parameters // with the portlet namespace if (request instanceof VaadinLiferayRequest) { - parameters.put( - ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE, - response.getPortletResponse().getNamespace()); + serviceUrlParameterName = response.getPortletResponse() + .getNamespace() + serviceUrlParameterName; } + parameters.put(ApplicationConstants.SERVICE_URL_PARAMETER_NAME, + serviceUrlParameterName); return parameters; } diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index 44c972462a..d7aaee6267 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -48,11 +48,7 @@ public class ApplicationConstants implements Serializable { public static final String SERVICE_URL = "serviceUrl"; - public static final String SERVICE_URL_PATH_AS_PARAMETER = "usePathParameter"; - - // Denotes the namespace which parameters should be prefixed with when - // passed as GET parameters. Currently only used by Liferay. - public static final String SERVICE_URL_PARAMETER_NAMESPACE = "pathParameterNS"; + public static final String SERVICE_URL_PARAMETER_NAME = "pathParameterName"; // Javadocs in ApplicationConfiguration should be updated if this is changed public static final String V_RESOURCE_PATH = "v-resourcePath"; diff --git a/shared/src/com/vaadin/shared/VaadinUriResolver.java b/shared/src/com/vaadin/shared/VaadinUriResolver.java new file mode 100644 index 0000000000..10edfe8aad --- /dev/null +++ b/shared/src/com/vaadin/shared/VaadinUriResolver.java @@ -0,0 +1,95 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.shared; + +import java.io.Serializable; + +import com.vaadin.shared.util.SharedUtil; + +public abstract class VaadinUriResolver implements Serializable { + + public String resolveVaadinUri(String vaadinUri) { + if (vaadinUri == null) { + return null; + } + if (vaadinUri.startsWith("theme://")) { + final String themeUri = getThemeUri(); + vaadinUri = themeUri + vaadinUri.substring(7); + } + + if (vaadinUri + .startsWith(ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX)) { + // getAppUri *should* always end with / + // substring *should* always start with / (published:///foo.bar + // without published://) + vaadinUri = ApplicationConstants.APP_PROTOCOL_PREFIX + + ApplicationConstants.PUBLISHED_FILE_PATH + + vaadinUri + .substring(ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX + .length()); + // Let translation of app:// urls take care of the rest + } + if (vaadinUri.startsWith(ApplicationConstants.APP_PROTOCOL_PREFIX)) { + String relativeUrl = vaadinUri + .substring(ApplicationConstants.APP_PROTOCOL_PREFIX + .length()); + String serviceUrl = getServiceUrl(); + String serviceUrlParameterName = getServiceUrlParameterName(); + if (serviceUrlParameterName != null) { + // Should put path in v-resourcePath parameter and append query + // params to base portlet url + String[] parts = relativeUrl.split("\\?", 2); + String path = parts[0]; + + // If there's a "?" followed by something, append it as a query + // string to the base URL + if (parts.length > 1) { + String appUrlParams = parts[1]; + serviceUrl = SharedUtil.addGetParameters(serviceUrl, + appUrlParams); + } + if (!path.startsWith("/")) { + path = '/' + path; + } + String pathParam = serviceUrlParameterName + "=" + + encodeQueryStringParameterValue(path); + serviceUrl = SharedUtil.addGetParameters(serviceUrl, pathParam); + vaadinUri = serviceUrl; + } else { + vaadinUri = serviceUrl + relativeUrl; + } + } + if (vaadinUri.startsWith(ApplicationConstants.VAADIN_PROTOCOL_PREFIX)) { + final String vaadinDirUri = getVaadinDirUrl(); + String relativeUrl = vaadinUri + .substring(ApplicationConstants.VAADIN_PROTOCOL_PREFIX + .length()); + vaadinUri = vaadinDirUri + relativeUrl; + } + + return vaadinUri; + } + + protected abstract String getVaadinDirUrl(); + + protected abstract String getServiceUrlParameterName(); + + protected abstract String getServiceUrl(); + + protected abstract String getThemeUri(); + + protected abstract String encodeQueryStringParameterValue(String queryString); +} diff --git a/shared/src/com/vaadin/shared/util/SharedUtil.java b/shared/src/com/vaadin/shared/util/SharedUtil.java index 7276f418fa..cc98d11abd 100644 --- a/shared/src/com/vaadin/shared/util/SharedUtil.java +++ b/shared/src/com/vaadin/shared/util/SharedUtil.java @@ -60,4 +60,45 @@ public class SharedUtil implements Serializable { */ public static final String SIZE_PATTERN = "^(-?\\d*(?:\\.\\d+)?)(%|px|em|rem|ex|in|cm|mm|pt|pc)?$"; + /** + * Adds the get parameters to the uri and returns the new uri that contains + * the parameters. + * + * @param uri + * The uri to which the parameters should be added. + * @param extraParams + * One or more parameters in the format "a=b" or "c=d&e=f". An + * empty string is allowed but will not modify the url. + * @return The modified URI with the get parameters in extraParams added. + */ + public static String addGetParameters(String uri, String extraParams) { + if (extraParams == null || extraParams.length() == 0) { + return uri; + } + // RFC 3986: The query component is indicated by the first question + // mark ("?") character and terminated by a number sign ("#") character + // or by the end of the URI. + String fragment = null; + int hashPosition = uri.indexOf('#'); + if (hashPosition != -1) { + // Fragment including "#" + fragment = uri.substring(hashPosition); + // The full uri before the fragment + uri = uri.substring(0, hashPosition); + } + + if (uri.contains("?")) { + uri += "&"; + } else { + uri += "?"; + } + uri += extraParams; + + if (fragment != null) { + uri += fragment; + } + + return uri; + } + } diff --git a/uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtml.java b/uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtml.java new file mode 100644 index 0000000000..96210b2027 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtml.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 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.tests.components.ui; + +import com.vaadin.annotations.JavaScript; +import com.vaadin.annotations.StyleSheet; +import com.vaadin.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; + +@JavaScript("uiDependency.js") +@StyleSheet("theme://uiDependency.css") +@Theme("tests-valo") +public class UiDependenciesInHtml extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + Label statusBox = new Label("Status box"); + statusBox.setId("statusBox"); + addComponent(statusBox); + + getPage().getJavaScript().execute("window.reportUiDependencyStatus();"); + } +} diff --git a/uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtmlTest.java b/uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtmlTest.java new file mode 100644 index 0000000000..188a0aea3e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtmlTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 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.tests.components.ui; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class UiDependenciesInHtmlTest extends SingleBrowserTest { + + @Test + public void testUiDependencisInHtml() { + openTestURL(); + + String statusText = findElement(By.id("statusBox")).getText(); + + Assert.assertEquals( + "Script loaded before vaadinBootstrap.js: true\nStyle tag before vaadin theme: true", + statusText); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/ui/uiDependency.js b/uitest/src/com/vaadin/tests/components/ui/uiDependency.js new file mode 100644 index 0000000000..4a5775c57f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/uiDependency.js @@ -0,0 +1,24 @@ +(function() { + var loadedBeforeVaadin = (window.vaadin === undefined); + + window.reportUiDependencyStatus = function() { + var styleIndex = 1000; + var themeIndex = -1; + + var stylesheets = document.querySelectorAll("link[rel=stylesheet]"); + for(var i = 0; i < stylesheets.length; i++) { + var stylesheet = stylesheets[i]; + var href = stylesheet.getAttribute("href"); + if (href.indexOf("uiDependency.css") > -1) { + styleIndex = i; + } else if (href.indexOf("styles.css" > -1)) { + themeIndex = i; + } + } + + var status = "Script loaded before vaadinBootstrap.js: " + loadedBeforeVaadin; + status += "
Style tag before vaadin theme: " + (styleIndex < themeIndex); + + document.getElementById("statusBox").innerHTML = status; + } +})(); \ No newline at end of file -- cgit v1.2.3 From b412ae97a659919b928fc28a3cb6500d75d514b2 Mon Sep 17 00:00:00 2001 From: Jonas Granvik Date: Mon, 12 Jan 2015 12:44:34 +0200 Subject: Add option to disable sending v-loc parameter in init request (#14460). Change-Id: Ie17e0621400c3397dc19b386974e231b6f82944c --- WebContent/VAADIN/vaadinBootstrap.js | 8 +++-- server/src/com/vaadin/server/BootstrapHandler.java | 6 ++++ server/src/com/vaadin/server/Constants.java | 1 + .../server/DefaultDeploymentConfiguration.java | 21 +++++++++++++ .../com/vaadin/server/DeploymentConfiguration.java | 9 ++++++ server/src/com/vaadin/server/Page.java | 6 ++++ .../AbstractDeploymentConfigurationTest.java | 5 +++ .../tests/util/MockDeploymentConfiguration.java | 6 ++++ .../DisableSendUrlAsParameters.java | 36 ++++++++++++++++++++++ .../DisableSendUrlAsParametersTest.java | 35 +++++++++++++++++++++ .../vaadin/tests/components/AbstractTestUI.java | 5 +++ 11 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParameters.java create mode 100644 uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParametersTest.java (limited to 'uitest/src') diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js index 53b213e110..89514dbcc2 100644 --- a/WebContent/VAADIN/vaadinBootstrap.js +++ b/WebContent/VAADIN/vaadinBootstrap.js @@ -136,7 +136,7 @@ params += extraParams; } - params += '&' + vaadin.getBrowserDetailsParameters(appId); + params += '&' + vaadin.getBrowserDetailsParameters(appId, getConfig('sendUrlsAsParameters')); var r; try { @@ -270,7 +270,7 @@ ws.pendingApps = null; } }, - getBrowserDetailsParameters: function(parentElementId) { + getBrowserDetailsParameters: function(parentElementId, sendUrlsAsParameters) { // Screen height and width var params = 'v-sh=' + window.screen.height; params += '&v-sw=' + window.screen.width; @@ -327,7 +327,9 @@ } // Location - params += '&v-loc=' + encodeURIComponent(location.href); + if (sendUrlsAsParameters !== false) { + params += '&v-loc=' + encodeURIComponent(location.href); + } // Window name if (window.name) { diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index e74f6d7c45..a9343a7e03 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -681,6 +681,12 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { appConfig.put(ApplicationConstants.SERVICE_URL, serviceUrl); } + boolean sendUrlsAsParameters = vaadinService + .getDeploymentConfiguration().isSendUrlsAsParameters(); + if (!sendUrlsAsParameters) { + appConfig.put("sendUrlsAsParameters", false); + } + return appConfig; } diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index 02a992a882..8036490333 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -136,6 +136,7 @@ public interface Constants { static final String SERVLET_PARAMETER_UI_PROVIDER = "UIProvider"; static final String SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING = "legacyPropertyToString"; static final String SERVLET_PARAMETER_SYNC_ID_CHECK = "syncIdCheck"; + static final String SERVLET_PARAMETER_SENDURLSASPARAMETERS = "sendUrlsAsParameters"; // Configurable parameter names static final String PARAMETER_VAADIN_RESOURCES = "Resources"; diff --git a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java index 22d5210eaa..b26e048431 100644 --- a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java @@ -59,6 +59,8 @@ public class DefaultDeploymentConfiguration extends */ public static final boolean DEFAULT_SYNC_ID_CHECK = true; + public static final boolean DEFAULT_SEND_URLS_AS_PARAMETERS = true; + private final Properties initParameters; private boolean productionMode; private boolean xsrfProtectionEnabled; @@ -69,6 +71,7 @@ public class DefaultDeploymentConfiguration extends private final Class systemPropertyBaseClass; private LegacyProperyToStringMode legacyPropertyToStringMode; private boolean syncIdCheck; + private boolean sendUrlsAsParameters; /** * Create a new deployment configuration instance. @@ -93,6 +96,7 @@ public class DefaultDeploymentConfiguration extends checkPushMode(); checkLegacyPropertyToString(); checkSyncIdCheck(); + checkSendUrlsAsParameters(); } private void checkLegacyPropertyToString() { @@ -255,6 +259,16 @@ public class DefaultDeploymentConfiguration extends return syncIdCheck; } + /** + * {@inheritDoc} + *

+ * The default value is true. + */ + @Override + public boolean isSendUrlsAsParameters() { + return sendUrlsAsParameters; + } + /** * {@inheritDoc} *

@@ -347,6 +361,13 @@ public class DefaultDeploymentConfiguration extends Boolean.toString(DEFAULT_SYNC_ID_CHECK)).equals("true"); } + private void checkSendUrlsAsParameters() { + sendUrlsAsParameters = getApplicationOrSystemProperty( + Constants.SERVLET_PARAMETER_SENDURLSASPARAMETERS, + Boolean.toString(DEFAULT_SEND_URLS_AS_PARAMETERS)).equals( + "true"); + } + private Logger getLogger() { return Logger.getLogger(getClass().getName()); } diff --git a/server/src/com/vaadin/server/DeploymentConfiguration.java b/server/src/com/vaadin/server/DeploymentConfiguration.java index 3c20518c39..968ec7c0c3 100644 --- a/server/src/com/vaadin/server/DeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DeploymentConfiguration.java @@ -110,6 +110,15 @@ public interface DeploymentConfiguration extends Serializable { */ public int getHeartbeatInterval(); + /** + * Returns whether the sending of URL's as GET and POST parameters in + * requests with content-type application/x-www-form-urlencoded + * is enabled or not. + * + * @return false if set to false or true otherwise + */ + public boolean isSendUrlsAsParameters(); + /** * Returns whether a session should be closed when all its open UIs have * been idle for longer than its configured maximum inactivity time. diff --git a/server/src/com/vaadin/server/Page.java b/server/src/com/vaadin/server/Page.java index 3ddf4862b2..74d79ade50 100644 --- a/server/src/com/vaadin/server/Page.java +++ b/server/src/com/vaadin/server/Page.java @@ -939,6 +939,12 @@ public class Page implements Serializable { * @return The browser location URI. */ public URI getLocation() { + if (location == null + && !uI.getSession().getConfiguration().isSendUrlsAsParameters()) { + throw new IllegalStateException("Location is not available as the " + + Constants.SERVLET_PARAMETER_SENDURLSASPARAMETERS + + " parameter is configured as false"); + } return location; } diff --git a/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java b/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java index 7370bd3fac..0518bea650 100644 --- a/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java +++ b/server/tests/src/com/vaadin/server/AbstractDeploymentConfigurationTest.java @@ -153,5 +153,10 @@ public class AbstractDeploymentConfigurationTest { return null; } + @Override + public boolean isSendUrlsAsParameters() { + return DefaultDeploymentConfiguration.DEFAULT_SEND_URLS_AS_PARAMETERS; + } + } } diff --git a/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java b/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java index 8eceaea53f..ddee23a9ec 100644 --- a/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java +++ b/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java @@ -21,6 +21,7 @@ public class MockDeploymentConfiguration extends private Map applicationOrSystemProperty = new HashMap(); private LegacyProperyToStringMode legacyPropertyToStringMode = LegacyProperyToStringMode.DISABLED; private boolean syncIdCheckEnabled = true; + private boolean sendUrlsAsParameters = true; @Override public boolean isProductionMode() { @@ -119,4 +120,9 @@ public class MockDeploymentConfiguration extends this.legacyPropertyToStringMode = legacyPropertyToStringMode; } + @Override + public boolean isSendUrlsAsParameters() { + return sendUrlsAsParameters; + } + } diff --git a/uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParameters.java b/uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParameters.java new file mode 100644 index 0000000000..d398ead622 --- /dev/null +++ b/uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParameters.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 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.tests.applicationservlet; + +import com.vaadin.launcher.CustomDeploymentConfiguration; +import com.vaadin.launcher.CustomDeploymentConfiguration.Conf; +import com.vaadin.server.Constants; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; + +@CustomDeploymentConfiguration({ @Conf(name = Constants.SERVLET_PARAMETER_SENDURLSASPARAMETERS, value = "false") }) +public class DisableSendUrlAsParameters extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + try { + log("Init location: " + getPage().getLocation()); + } catch (IllegalStateException e) { + log("Init location exception: " + e.getMessage()); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParametersTest.java b/uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParametersTest.java new file mode 100644 index 0000000000..f10f281646 --- /dev/null +++ b/uitest/src/com/vaadin/tests/applicationservlet/DisableSendUrlAsParametersTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2014 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.tests.applicationservlet; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class DisableSendUrlAsParametersTest extends SingleBrowserTest { + + @Test + public void testInitLocation() { + openTestURL(); + + String logRow = getLogRow(0); + + Assert.assertEquals( + "1. Init location exception: Location is not available as the sendUrlsAsParameters parameter is configured as false", + logRow); + } +} diff --git a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java index 3a7d42e29c..dba055a65a 100644 --- a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java +++ b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java @@ -46,6 +46,11 @@ public abstract class AbstractTestUI extends UI { } protected void warnIfWidgetsetMaybeNotCompiled() { + // Can't check location if sendUrlAsParameters is disabled + if (!getSession().getConfiguration().isSendUrlsAsParameters()) { + return; + } + // Ignore if using debug mode String query = getPage().getLocation().getQuery(); if (query != null && query.matches(".*[&?]gwt\\.codesvr.*")) { -- cgit v1.2.3 From 8eeeb35544522b96cba07795f336a14e2737c7ea Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 13 Jan 2015 12:42:22 +0200 Subject: Fix remaining issues for NativeSelect blur/focus events (#6847) * Do not spam focus/blur events to the server * Receive focus blur events no matter which constructor is used * Run test on all browsers Change-Id: I7d548397e6df3a375f9263c695a53c801d9c5c4a --- client/src/com/vaadin/client/EventHelper.java | 55 ++++++++++++++-- client/src/com/vaadin/client/ui/VNativeSelect.java | 17 ++--- .../ui/nativeselect/NativeSelectConnector.java | 21 +++++- server/src/com/vaadin/ui/NativeSelect.java | 3 + .../tests/src/com/vaadin/ui/NativeSelectTest.java | 54 +++++++++++++++ .../NativeSelectsFocusAndBlurListenerTests.java | 76 +++++----------------- 6 files changed, 147 insertions(+), 79 deletions(-) create mode 100644 server/tests/src/com/vaadin/ui/NativeSelectTest.java (limited to 'uitest/src') diff --git a/client/src/com/vaadin/client/EventHelper.java b/client/src/com/vaadin/client/EventHelper.java index a1cb75527d..f251215d41 100644 --- a/client/src/com/vaadin/client/EventHelper.java +++ b/client/src/com/vaadin/client/EventHelper.java @@ -25,6 +25,7 @@ import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.ui.Widget; /** * Helper class for attaching/detaching handlers for Vaadin client side @@ -61,7 +62,7 @@ public class EventHelper { * @param connector * The connector to update. Must implement focusHandler. * @param handlerRegistration - * The old registration reference or null no handler has been + * The old registration reference or null if no handler has been * registered previously * @return a new registration handler that can be used to unregister the * handler later @@ -69,7 +70,27 @@ public class EventHelper { public static HandlerRegistration updateFocusHandler( T connector, HandlerRegistration handlerRegistration) { return updateHandler(connector, FOCUS, handlerRegistration, - FocusEvent.getType()); + FocusEvent.getType(), connector.getWidget()); + } + + /** + * Adds or removes a focus handler depending on if the connector has focus + * listeners on the server side or not. + * + * @param connector + * The connector to update. Must implement focusHandler. + * @param handlerRegistration + * The old registration reference or null if no handler has been + * registered previously + * @param widget + * The widget which emits focus events + * @return a new registration handler that can be used to unregister the + * handler later + */ + public static HandlerRegistration updateFocusHandler( + T connector, HandlerRegistration handlerRegistration, Widget widget) { + return updateHandler(connector, FOCUS, handlerRegistration, + FocusEvent.getType(), widget); } /** @@ -79,7 +100,7 @@ public class EventHelper { * @param connector * The connector to update. Must implement BlurHandler. * @param handlerRegistration - * The old registration reference or null no handler has been + * The old registration reference or null if no handler has been * registered previously * @return a new registration handler that can be used to unregister the * handler later @@ -87,16 +108,36 @@ public class EventHelper { public static HandlerRegistration updateBlurHandler( T connector, HandlerRegistration handlerRegistration) { return updateHandler(connector, BLUR, handlerRegistration, - BlurEvent.getType()); + BlurEvent.getType(), connector.getWidget()); + } + + /** + * Adds or removes a blur handler depending on if the connector has blur + * listeners on the server side or not. + * + * @param connector + * The connector to update. Must implement BlurHandler. + * @param handlerRegistration + * The old registration reference or null if no handler has been + * registered previously + * @param widget + * The widget which emits blur events + * + * @return a new registration handler that can be used to unregister the + * handler later + */ + public static HandlerRegistration updateBlurHandler( + T connector, HandlerRegistration handlerRegistration, Widget widget) { + return updateHandler(connector, BLUR, handlerRegistration, + BlurEvent.getType(), widget); } private static HandlerRegistration updateHandler( ComponentConnector connector, String eventIdentifier, - HandlerRegistration handlerRegistration, Type type) { + HandlerRegistration handlerRegistration, Type type, Widget widget) { if (connector.hasEventListener(eventIdentifier)) { if (handlerRegistration == null) { - handlerRegistration = connector.getWidget().addDomHandler( - (H) connector, type); + handlerRegistration = widget.addDomHandler((H) connector, type); } } else if (handlerRegistration != null) { handlerRegistration.removeHandler(); diff --git a/client/src/com/vaadin/client/ui/VNativeSelect.java b/client/src/com/vaadin/client/ui/VNativeSelect.java index 879c54cae8..330442b550 100644 --- a/client/src/com/vaadin/client/ui/VNativeSelect.java +++ b/client/src/com/vaadin/client/ui/VNativeSelect.java @@ -19,9 +19,7 @@ package com.vaadin.client.ui; import java.util.ArrayList; import java.util.Iterator; -import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.user.client.ui.ListBox; import com.vaadin.client.BrowserInfo; import com.vaadin.client.UIDL; @@ -119,14 +117,6 @@ public class VNativeSelect extends VOptionGroupBase implements Field { } } - public void addFocusHandler(FocusHandler handler) { - select.addFocusHandler(handler); - } - - public void addBlurHandler(BlurHandler handler) { - select.addBlurHandler(handler); - } - @Override public void setHeight(String height) { select.setHeight(height); @@ -154,4 +144,11 @@ public class VNativeSelect extends VOptionGroupBase implements Field { select.setFocus(true); } + /** + * @return the root select widget + */ + public ListBox getSelect() { + return getOptionsContainer(); + } + } diff --git a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java index c52b762e58..938903da9a 100644 --- a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java +++ b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java @@ -20,6 +20,9 @@ import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.vaadin.client.EventHelper; +import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.ui.VNativeSelect; import com.vaadin.client.ui.optiongroup.OptionGroupBaseConnector; import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; @@ -30,10 +33,19 @@ import com.vaadin.ui.NativeSelect; public class NativeSelectConnector extends OptionGroupBaseConnector implements BlurHandler, FocusHandler { + private HandlerRegistration focusHandlerRegistration = null; + private HandlerRegistration blurHandlerRegistration = null; + public NativeSelectConnector() { super(); - getWidget().addFocusHandler(this); - getWidget().addBlurHandler(this); + } + + @OnStateChange("registeredEventListeners") + private void onServerEventListenerChanged() { + focusHandlerRegistration = EventHelper.updateFocusHandler(this, + focusHandlerRegistration, getWidget().getSelect()); + blurHandlerRegistration = EventHelper.updateBlurHandler(this, + blurHandlerRegistration, getWidget().getSelect()); } @Override @@ -43,11 +55,16 @@ public class NativeSelectConnector extends OptionGroupBaseConnector implements @Override public void onFocus(FocusEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side getRpcProxy(FocusAndBlurServerRpc.class).focus(); } @Override public void onBlur(BlurEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side getRpcProxy(FocusAndBlurServerRpc.class).blur(); } + } diff --git a/server/src/com/vaadin/ui/NativeSelect.java b/server/src/com/vaadin/ui/NativeSelect.java index ee7bfc3e5c..137d57f677 100644 --- a/server/src/com/vaadin/ui/NativeSelect.java +++ b/server/src/com/vaadin/ui/NativeSelect.java @@ -56,14 +56,17 @@ public class NativeSelect extends AbstractSelect implements public NativeSelect(String caption, Collection options) { super(caption, options); + registerRpc(focusBlurRpc); } public NativeSelect(String caption, Container dataSource) { super(caption, dataSource); + registerRpc(focusBlurRpc); } public NativeSelect(String caption) { super(caption); + registerRpc(focusBlurRpc); } /** diff --git a/server/tests/src/com/vaadin/ui/NativeSelectTest.java b/server/tests/src/com/vaadin/ui/NativeSelectTest.java new file mode 100644 index 0000000000..7e2a04ef1c --- /dev/null +++ b/server/tests/src/com/vaadin/ui/NativeSelectTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2014 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.ui; + +import java.util.Collections; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.data.util.IndexedContainer; + +public class NativeSelectTest { + + @Test + public void rpcRegisteredConstructorNoArg() { + assertFocusRpcRegistered(new NativeSelect()); + } + + @Test + public void rpcRegisteredConstructorString() { + assertFocusRpcRegistered(new NativeSelect("foo")); + } + + @Test + public void rpcRegisteredConstructorStringCollection() { + assertFocusRpcRegistered(new NativeSelect("foo", + Collections.singleton("Hello"))); + } + + @Test + public void rpcRegisteredConstructorStringContainer() { + assertFocusRpcRegistered(new NativeSelect("foo", new IndexedContainer())); + } + + private void assertFocusRpcRegistered(NativeSelect s) { + Assert.assertNotNull( + "RPC is not correctly registered", + s.getRpcManager("com.vaadin.shared.communication.FieldRpc$FocusAndBlurServerRpc")); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsFocusAndBlurListenerTests.java b/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsFocusAndBlurListenerTests.java index 29c8c27883..bf81ca4390 100644 --- a/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsFocusAndBlurListenerTests.java +++ b/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsFocusAndBlurListenerTests.java @@ -15,102 +15,58 @@ */ package com.vaadin.tests.components.nativeselect; -import java.util.Collections; -import java.util.List; - import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; -import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.elements.NativeSelectElement; import com.vaadin.tests.tb3.MultiBrowserTest; -/** - * - * @since - * @author Vaadin Ltd - */ public class NativeSelectsFocusAndBlurListenerTests extends MultiBrowserTest { - /* - * (non-Javadoc) - * - * @see com.vaadin.tests.tb3.MultiBrowserTest#getBrowsersToTest() - */ - @Override - public List getBrowsersToTest() { - return Collections.singletonList(Browser.CHROME - .getDesiredCapabilities()); - } - @Test - public void testFocusListener() throws InterruptedException { + public void testFocusAndBlurListener() throws InterruptedException { setDebug(true); openTestURL(); - Thread.sleep(1000); + Thread.sleep(200); menu("Component"); menuSub("Listeners"); menuSub("Focus listener"); - - getDriver().findElement(By.tagName("body")).click(); - - WebElement select = getDriver().findElement(By.tagName("select")); - select.click(); - - String bodytext = getDriver().findElement(By.tagName("body")).getText(); - - Assert.assertTrue(bodytext.contains("FocusEvent")); - - } - - @Test - public void testBlurListener() throws InterruptedException { - setDebug(true); - openTestURL(); - Thread.sleep(1000); menu("Component"); menuSub("Listeners"); menuSub("Blur listener"); - getDriver().findElement(By.tagName("body")).click(); - - WebElement select = getDriver().findElement(By.tagName("select")); - select.click(); + findElement(By.tagName("body")).click(); + NativeSelectElement s = $(NativeSelectElement.class).first(); + s.selectByText("Item 3"); getDriver().findElement(By.tagName("body")).click(); - String bodytext = getDriver().findElement(By.tagName("body")).getText(); - - Assert.assertTrue(bodytext.contains("BlurEvent")); + // Somehow selectByText causes focus + blur + focus + blur on + // Chrome/PhantomJS + if (BrowserUtil.isChrome(getDesiredCapabilities()) + || BrowserUtil.isPhantomJS(getDesiredCapabilities())) { + Assert.assertEquals("4. FocusEvent", getLogRow(1)); + Assert.assertEquals("5. BlurEvent", getLogRow(0)); + } else { + Assert.assertEquals("2. FocusEvent", getLogRow(1)); + Assert.assertEquals("3. BlurEvent", getLogRow(0)); + } } - /* - * (non-Javadoc) - * - * @see com.vaadin.tests.tb3.AbstractTB3Test#getUIClass() - */ @Override protected Class getUIClass() { return NativeSelects.class; } - /** - * @since - * @param string - */ private void menuSub(String string) { getDriver().findElement(By.xpath("//span[text() = '" + string + "']")) .click(); new Actions(getDriver()).moveByOffset(100, 0).build().perform(); } - /** - * @since - * @param string - */ private void menu(String string) { getDriver().findElement(By.xpath("//span[text() = '" + string + "']")) .click(); -- cgit v1.2.3