diff options
Diffstat (limited to 'src/com/vaadin/terminal/gwt/client/ApplicationConnection.java')
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ApplicationConnection.java | 250 |
1 files changed, 143 insertions, 107 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index f0470c8ee8..fb7af1404c 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -27,6 +27,7 @@ import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; +import com.google.gwt.http.client.URL; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; @@ -35,21 +36,23 @@ import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; -import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.shared.ComponentState; +import com.vaadin.shared.communication.MethodInvocation; +import com.vaadin.shared.communication.SharedState; +import com.vaadin.shared.communication.UidlValue; import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage; +import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadEvent; +import com.vaadin.terminal.gwt.client.ResourceLoader.ResourceLoadListener; import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper; import com.vaadin.terminal.gwt.client.communication.JsonDecoder; import com.vaadin.terminal.gwt.client.communication.JsonEncoder; -import com.vaadin.terminal.gwt.client.communication.MethodInvocation; import com.vaadin.terminal.gwt.client.communication.RpcManager; import com.vaadin.terminal.gwt.client.communication.SerializerMap; -import com.vaadin.terminal.gwt.client.communication.SharedState; import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; import com.vaadin.terminal.gwt.client.communication.Type; -import com.vaadin.terminal.gwt.client.communication.UidlValue; import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector; import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; import com.vaadin.terminal.gwt.client.ui.VContextMenu; @@ -75,6 +78,19 @@ import com.vaadin.terminal.gwt.server.AbstractCommunicationManager; * Entry point classes (widgetsets) define <code>onModuleLoad()</code>. */ public class ApplicationConnection { + public static final String APP_REQUEST_PATH = "APP/"; + + public static final String UIDL_REQUEST_PATH = "UIDL/"; + + public static final String APP_PROTOCOL_PREFIX = "app://"; + + public static final String V_RESOURCE_PATH = "v-resourcePath"; + + public static final String CONNECTOR_PROTOCOL_PREFIX = "connector://"; + + public static final String CONNECTOR_RESOURCE_PREFIX = APP_REQUEST_PATH + + "CONNECTOR"; + // This indicates the whole page is generated by us (not embedded) public static final String GENERATED_BODY_CLASSNAME = "v-generated-body"; @@ -131,7 +147,7 @@ public class ApplicationConnection { */ public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh"; - private final boolean debugLogging = false; + private final boolean debugLogging = true || false; // will hold the UIDL security key (for XSS protection) once received private String uidlSecurityKey = "init"; @@ -506,12 +522,7 @@ public class ApplicationConnection { final String payload = uidlSecurityKey + VAR_BURST_SEPARATOR + requestData; VConsole.log("Making UIDL Request with params: " + payload); - String uri; - if (configuration.usePortletURLs()) { - uri = configuration.getPortletUidlURLBase(); - } else { - uri = getAppUri() + "UIDL"; - } + String uri = translateVaadinUri(APP_PROTOCOL_PREFIX + UIDL_REQUEST_PATH); if (extraParams != null && extraParams.length() > 0) { uri = addGetParameters(uri, extraParams); @@ -538,11 +549,13 @@ public class ApplicationConnection { final boolean synchronous) { if (!synchronous) { RequestCallback requestCallback = new RequestCallback() { + @Override public void onError(Request request, Throwable exception) { showCommunicationError(exception.getMessage(), -1); endRequest(); } + @Override public void onResponseReceived(Request request, Response response) { VConsole.log("Server visit took " @@ -868,6 +881,7 @@ public class ApplicationConnection { } // deferring to avoid flickering Scheduler.get().scheduleDeferred(new Command() { + @Override public void execute() { if (!hasActiveRequest()) { hideLoadingIndicator(); @@ -1067,6 +1081,14 @@ public class ApplicationConnection { json.getValueMap("typeMappings"), widgetSet); } + VConsole.log("Handling resource dependencies"); + if (json.containsKey("scriptDependencies")) { + loadScriptDependencies(json.getJSStringArray("scriptDependencies")); + } + if (json.containsKey("styleDependencies")) { + loadStyleDependencies(json.getJSStringArray("styleDependencies")); + } + handleUIDLDuration.logDuration( " * Handling type mappings from server completed", 10); /* @@ -1077,6 +1099,7 @@ public class ApplicationConnection { } Command c = new Command() { + @Override public void execute() { handleUIDLDuration.logDuration(" * Loading widgets completed", 10); @@ -1608,7 +1631,72 @@ public class ApplicationConnection { } }; - ApplicationConfiguration.runWhenWidgetsLoaded(c); + ApplicationConfiguration.runWhenDependenciesLoaded(c); + } + + private void loadStyleDependencies(JsArrayString dependencies) { + // Assuming no reason to interpret in a defined order + ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { + @Override + public void onLoad(ResourceLoadEvent event) { + ApplicationConfiguration.endDependencyLoading(); + } + + @Override + public void onError(ResourceLoadEvent event) { + VConsole.error(event.getResourceUrl() + + " could not be loaded, or the load detection failed because the stylesheet is empty."); + // The show must go on + onLoad(event); + } + }; + ResourceLoader loader = ResourceLoader.get(); + for (int i = 0; i < dependencies.length(); i++) { + String url = translateVaadinUri(dependencies.get(i)); + ApplicationConfiguration.startDependencyLoading(); + loader.loadStylesheet(url, resourceLoadListener); + } + } + + private void loadScriptDependencies(final JsArrayString dependencies) { + if (dependencies.length() == 0) { + return; + } + + // Listener that loads the next when one is completed + ResourceLoadListener resourceLoadListener = new ResourceLoadListener() { + @Override + public void onLoad(ResourceLoadEvent event) { + if (dependencies.length() != 0) { + String url = translateVaadinUri(dependencies.shift()); + ApplicationConfiguration.startDependencyLoading(); + // Load next in chain (hopefully already preloaded) + event.getResourceLoader().loadScript(url, this); + } + // Call start for next before calling end for current + ApplicationConfiguration.endDependencyLoading(); + } + + @Override + public void onError(ResourceLoadEvent event) { + VConsole.error(event.getResourceUrl() + " could not be loaded."); + // The show must go on + onLoad(event); + } + }; + + ResourceLoader loader = ResourceLoader.get(); + + // Start chain by loading first + String url = translateVaadinUri(dependencies.shift()); + ApplicationConfiguration.startDependencyLoading(); + loader.loadScript(url, resourceLoadListener); + + // Preload all remaining + for (int i = 0; i < dependencies.length(); i++) { + String preloadUrl = translateVaadinUri(dependencies.get(i)); + loader.preloadResource(preloadUrl, null); + } } // Redirect browser, null reloads current page @@ -1669,6 +1757,7 @@ public class ApplicationConnection { } private final ScheduledCommand sendPendingCommand = new ScheduledCommand() { + @Override public void execute() { deferedSendPending = false; doSendPendingVariableChanges(); @@ -2214,8 +2303,42 @@ public class ApplicationConnection { } uidlUri = themeUri + uidlUri.substring(7); } - if (uidlUri.startsWith("app://")) { - uidlUri = getAppUri() + uidlUri.substring(6); + + if (uidlUri.startsWith(CONNECTOR_PROTOCOL_PREFIX)) { + // getAppUri *should* always end with / + // substring *should* always start with / (connector:///foo.bar + // without connector://) + uidlUri = APP_PROTOCOL_PREFIX + CONNECTOR_RESOURCE_PREFIX + + uidlUri.substring(CONNECTOR_PROTOCOL_PREFIX.length()); + // Let translation of app:// urls take care of the rest + } + if (uidlUri.startsWith(APP_PROTOCOL_PREFIX)) { + String relativeUrl = uidlUri + .substring(APP_PROTOCOL_PREFIX.length()); + if (getConfiguration().usePortletURLs()) { + // Should put path in v-resourcePath parameter and append query + // params to base portlet url + String[] parts = relativeUrl.split("\\?", 2); + String path = parts[0]; + + String url = getConfiguration().getPortletResourceUrl(); + + // 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]; + url = addGetParameters(url, appUrlParams); + } + if (!path.startsWith("/")) { + path = '/' + path; + } + String pathParam = V_RESOURCE_PATH + "=" + + URL.encodeQueryString(path); + url = addGetParameters(url, pathParam); + uidlUri = url; + } else { + uidlUri = getAppUri() + relativeUrl; + } } return uidlUri; } @@ -2242,6 +2365,7 @@ public class ApplicationConnection { this.url = url; } + @Override public void notificationHidden(HideEvent event) { redirect(url); } @@ -2250,57 +2374,8 @@ public class ApplicationConnection { /* Extended title handling */ - /** - * Data showed in tooltips are stored centrilized as it may be needed in - * varios place: caption, layouts, and in owner components themselves. - * - * Updating TooltipInfo is done in updateComponent method. - * - */ - public TooltipInfo getTooltipTitleInfo(ComponentConnector titleOwner, - Object key) { - if (null == titleOwner) { - return null; - } - return connectorMap.getTooltipInfo(titleOwner, key); - } - private final VTooltip tooltip = new VTooltip(this); - /** - * Component may want to delegate Tooltip handling to client. Layouts add - * Tooltip (description, errors) to caption, but some components may want - * them to appear one other elements too. - * - * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS - * - * @param event - * @param owner - */ - public void handleTooltipEvent(Event event, ComponentConnector owner) { - tooltip.handleTooltipEvent(event, owner, null); - - } - - /** - * Component may want to delegate Tooltip handling to client. Layouts add - * Tooltip (description, errors) to caption, but some components may want - * them to appear one other elements too. - * - * Events wanted by this handler are same as in Tooltip.TOOLTIP_EVENTS - * - * @param event - * @param owner - * @param key - * the key for tooltip if this is "additional" tooltip, null for - * components "main tooltip" - */ - public void handleTooltipEvent(Event event, ComponentConnector owner, - Object key) { - tooltip.handleTooltipEvent(event, owner, key); - - } - private ConnectorMap connectorMap = GWT.create(ConnectorMap.class); protected String getUidlSecurityKey() { @@ -2328,34 +2403,6 @@ public class ApplicationConnection { } /** - * If component has several tooltips in addition to the one provided by - * {@link com.vaadin.ui.AbstractComponent}, component can register them with - * this method. - * <p> - * Component must also pipe events to - * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} method. - * <p> - * This method can also be used to deregister tooltips by using null as - * tooltip - * - * @param paintable - * Paintable "owning" this tooltip - * @param key - * key assosiated with given tooltip. Can be any object. For - * example a related dom element. Same key must be given for - * {@link #handleTooltipEvent(Event, ComponentConnector, Object)} - * method. - * - * @param tooltip - * the TooltipInfo object containing details shown in tooltip, - * null if deregistering tooltip - */ - public void registerTooltip(ComponentConnector paintable, Object key, - TooltipInfo tooltip) { - connectorMap.registerTooltip(paintable, key, tooltip); - } - - /** * Gets the {@link ApplicationConfiguration} for the current application. * * @see ApplicationConfiguration @@ -2437,15 +2484,15 @@ public class ApplicationConnection { // connectorMap.unregisterConnector(p); } + /** + * Get VTooltip instance related to application connection + * + * @return VTooltip instance + */ public VTooltip getVTooltip() { return tooltip; } - @Deprecated - public void handleTooltipEvent(Event event, Widget owner, Object key) { - handleTooltipEvent(event, getConnectorMap().getConnector(owner), key); - } - /** * Method provided for backwards compatibility. Duties previously done by * this method is now handled by the state change event handler in @@ -2474,17 +2521,6 @@ public class ApplicationConnection { } @Deprecated - public void handleTooltipEvent(Event event, Widget owner) { - handleTooltipEvent(event, getConnectorMap().getConnector(owner)); - - } - - @Deprecated - public void registerTooltip(Widget owner, Object key, TooltipInfo info) { - registerTooltip(getConnectorMap().getConnector(owner), key, info); - } - - @Deprecated public boolean hasEventListeners(Widget widget, String eventIdentifier) { return hasEventListeners(getConnectorMap().getConnector(widget), eventIdentifier); |