summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--WebContent/VAADIN/themes/tests-valo/uiDependency.css0
-rw-r--r--client/src/com/vaadin/client/ApplicationConfiguration.java11
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java128
-rw-r--r--client/src/com/vaadin/client/communication/AtmospherePushConnection.java3
-rw-r--r--client/src/com/vaadin/client/communication/Heartbeat.java3
-rw-r--r--client/src/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java5
-rw-r--r--client/tests/src/com/vaadin/client/ApplicationConnectionURLGenerationTest.java10
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java106
-rw-r--r--server/src/com/vaadin/server/communication/PortletBootstrapHandler.java16
-rw-r--r--shared/src/com/vaadin/shared/ApplicationConstants.java6
-rw-r--r--shared/src/com/vaadin/shared/VaadinUriResolver.java95
-rw-r--r--shared/src/com/vaadin/shared/util/SharedUtil.java41
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtml.java38
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UiDependenciesInHtmlTest.java37
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/uiDependency.js24
15 files changed, 398 insertions, 125 deletions
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
--- /dev/null
+++ b/WebContent/VAADIN/themes/tests-valo/uiDependency.css
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 {
* <code>false</code> 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 <code>v-resourcePath</code>
*/
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<? extends UI> 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 += "<br />Style tag before vaadin theme: " + (styleIndex < themeIndex);
+
+ document.getElementById("statusBox").innerHTML = status;
+ }
+})(); \ No newline at end of file