* Send the whole window location, not just fragment, in bootstrap and when the fragment changes
* BrowserDetails now has URI getLocation() instead of String getUriFragment()
* Keep FragmentChangeListeners as-is, should perhaps change to LocationChangeListeners at some point
* Implement Page.getFragment() by means of Page.getLocation()
* Differentiate between no fragment (null) and empty fragment ("") as java.net.URI does
Change-Id: I1da1ea0664304d0c121a57e85d127fe48605e940
url += '&vh=' + pe.offsetHeight;
}
- // Uri fragment
- if (location.hash) {
- //Remove initial #
- url += '&fr=' + encodeURIComponent(location.hash.replace(/^#/, ""));
- }
+ // Location
+ url += '&loc=' + encodeURIComponent(location.href);
+
// Window name
if (window.name) {
url += '&wn=' + encodeURIComponent(window.name);
scrollIntoView(connector);
}
- if (uidl.hasAttribute(UIConstants.FRAGMENT_VARIABLE)) {
- getWidget().currentFragment = uidl
- .getStringAttribute(UIConstants.FRAGMENT_VARIABLE);
+ if (uidl.hasAttribute(UIConstants.LOCATION_VARIABLE)) {
+ String location = uidl
+ .getStringAttribute(UIConstants.LOCATION_VARIABLE);
+ int fragmentIndex = location.indexOf('#');
+ if (fragmentIndex >= 0) {
+ getWidget().currentFragment = location
+ .substring(fragmentIndex + 1);
+ }
if (!getWidget().currentFragment.equals(History.getToken())) {
History.newItem(getWidget().currentFragment, true);
}
- } else {
- // Initial request for which the server doesn't yet have a fragment
- // (and haven't shown any interest in getting one)
- getWidget().currentFragment = History.getToken();
-
- // Include current fragment in the next request
- client.updateVariable(getWidget().id,
- UIConstants.FRAGMENT_VARIABLE, getWidget().currentFragment,
- false);
}
if (firstPaint) {
public void onValueChange(ValueChangeEvent<String> event) {
String newFragment = event.getValue();
- // Send the new fragment to the server if it has changed
+ // Send the location to the server if the fragment has changed
if (!newFragment.equals(currentFragment) && connection != null) {
currentFragment = newFragment;
- connection.updateVariable(id, UIConstants.FRAGMENT_VARIABLE,
- newFragment, true);
+ connection.updateVariable(id, UIConstants.LOCATION_VARIABLE,
+ Window.Location.getHref(), true);
}
}
};
@Override
public String getState() {
String fragment = getFragment();
- if (fragment.startsWith("!")) {
- return fragment.substring(1);
- } else {
+ if (fragment == null || !fragment.startsWith("!")) {
return "";
+ } else {
+ return fragment.substring(1);
}
}
// Check for an existing UI based on window.name
BrowserDetails browserDetails = request.getBrowserDetails();
boolean hasBrowserDetails = browserDetails != null
- && browserDetails.getUriFragment() != null;
+ && browserDetails.getLocation() != null;
Map<String, Integer> retainOnRefreshUIs = session
.getPreserveOnRefreshUIs();
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
public BrowserDetails getBrowserDetails() {
return new BrowserDetails() {
@Override
- public String getUriFragment() {
- String fragment = secondRequest.getParameter("fr");
- if (fragment == null) {
- return "";
+ public URI getLocation() {
+ String location = secondRequest.getParameter("loc");
+ if (location == null) {
+ return null;
} else {
- return fragment;
+ try {
+ return new URI(location);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(
+ "Invalid location URI received from client", e);
+ }
}
}
import java.io.Serializable;
import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.EventObject;
import java.util.Iterator;
import java.util.LinkedList;
private EventRouter eventRouter;
- /**
- * The current URI fragment.
- */
- private String fragment;
-
private final UI uI;
private int browserWindowWidth = -1;
private JavaScript javaScript;
+ /**
+ * The current browser location.
+ */
+ private URI location;
+
public Page(UI uI) {
this.uI = uI;
}
}
/**
- * Sets URI fragment. Optionally fires a {@link FragmentChangedEvent}
+ * Sets the fragment part in the current location URI. Optionally fires a
+ * {@link FragmentChangedEvent}.
+ * <p>
+ * The fragment is the optional last component of a URI, prefixed with a
+ * hash sign ("#").
+ * <p>
+ * Passing <code>null</code> as <code>newFragment</code> clears the fragment
+ * (no "#" in the URI); passing an empty string sets an empty fragment (a
+ * trailing "#" in the URI.) This is consistent with the semantics of
+ * {@link java.net.URI}.
*
* @param newFragment
- * id of the new fragment
+ * The new fragment.
* @param fireEvent
* true to fire event
+ *
+ * @see #getFragment()
+ * @see #setLocation(URI)
* @see FragmentChangedEvent
* @see Page.FragmentChangedListener
+ *
*/
public void setFragment(String newFragment, boolean fireEvents) {
- if (newFragment == null) {
- throw new NullPointerException("The fragment may not be null");
- }
- if (!newFragment.equals(fragment)) {
- fragment = newFragment;
+ String oldFragment = location.getFragment();
+ if (newFragment == null && oldFragment != null
+ || !newFragment.equals(oldFragment)) {
+ try {
+ location = new URI(location.getScheme(),
+ location.getSchemeSpecificPart(), newFragment);
+ } catch (URISyntaxException e) {
+ // This should not actually happen as the fragment syntax is not
+ // constrained
+ throw new RuntimeException(e);
+ }
if (fireEvents) {
fireEvent(new FragmentChangedEvent(this, newFragment));
}
}
/**
- * Gets currently set URI fragment.
+ * Gets the currently set URI fragment.
* <p>
- * To listen changes in fragment, hook a
+ * Returns <code>null</code> if there is no fragment and an empty string if
+ * there is an empty fragment.
+ * <p>
+ * To listen to changes in fragment, hook a
* {@link Page.FragmentChangedListener}.
*
- * @return the current fragment in browser uri or null if not known
+ * @return the current fragment in browser location URI.
+ *
+ * @see #getLocation()
+ * @see #setFragment(String)
+ * @see #addFragmentChangedListener(FragmentChangedListener)
*/
public String getFragment() {
- return fragment;
+ return location.getFragment();
}
public void init(VaadinRequest request) {
BrowserDetails browserDetails = request.getBrowserDetails();
if (browserDetails != null) {
- fragment = browserDetails.getUriFragment();
+ location = browserDetails.getLocation();
}
}
notifications = null;
}
- if (fragment != null) {
- target.addAttribute(UIConstants.FRAGMENT_VARIABLE, fragment);
+ if (location != null) {
+ target.addAttribute(UIConstants.LOCATION_VARIABLE,
+ location.toString());
}
}
/**
- * Navigates this page to the given URL. The contents of this page in the
- * browser is replaced with whatever is returned for the given URL.
+ * Navigates this page to the given URI. The contents of this page in the
+ * browser is replaced with whatever is returned for the given URI.
*
- * @param url
- * the URL to show
+ * @param uri
+ * the URI to show
*/
- public void setLocation(String url) {
- openList.add(new OpenResource(url, null, -1, -1, BORDER_DEFAULT));
+ public void setLocation(String uri) {
+ openList.add(new OpenResource(uri, null, -1, -1, BORDER_DEFAULT));
uI.markAsDirty();
}
+ /**
+ * Navigates this page to the given URI. The contents of this page in the
+ * browser is replaced with whatever is returned for the given URI.
+ *
+ * @param uri
+ * the URI to show
+ */
+ public void setLocation(URI uri) {
+ setLocation(uri.toString());
+ }
+
+ /**
+ * Returns the location URI of this page, as reported by the browser. Note
+ * that this may not be consistent with the server URI the application is
+ * deployed in due to potential proxies, redirections and similar.
+ *
+ * @return The browser location URI.
+ */
+ public URI getLocation() {
+ return location;
+ }
+
+ /**
+ * For internal use only. Used to update the server-side location when the
+ * client-side location changes.
+ */
+ public void updateLocation(String location) {
+ try {
+ String oldFragment = this.location.getFragment();
+ this.location = new URI(location);
+ String newFragment = this.location.getFragment();
+ if (newFragment == null && oldFragment != null
+ || !newFragment.equals(oldFragment)) {
+ fireEvent(new FragmentChangedEvent(this, newFragment));
+ }
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* Opens the given URL in a window with the given name.
* <p>
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.util.Locale;
import java.util.Map;
public BrowserDetails getBrowserDetails() {
return new BrowserDetails() {
@Override
- public String getUriFragment() {
+ public URI getLocation() {
return null;
}
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
+import java.net.URI;
import java.util.Locale;
import java.util.Map;
@Deprecated
public interface BrowserDetails extends Serializable {
/**
- * Gets the URI hash fragment for the request. This is typically used to
- * encode navigation within an application.
+ * Gets the URI in the browser address bar, including the fragment
+ * (Javascript window.location)
*
- * @return the URI hash fragment
+ * @return the browser location URI
*/
- public String getUriFragment();
+ public URI getLocation();
/**
* Gets the value of window.name from the browser. This can be used to
package com.vaadin.server;
+import java.net.URI;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;
public BrowserDetails getBrowserDetails() {
return new BrowserDetails() {
@Override
- public String getUriFragment() {
+ public URI getLocation() {
return null;
}
actionManager.handleActions(variables, this);
}
- if (variables.containsKey(UIConstants.FRAGMENT_VARIABLE)) {
- String fragment = (String) variables
- .get(UIConstants.FRAGMENT_VARIABLE);
- getPage().setFragment(fragment, true);
+ if (variables.containsKey(UIConstants.LOCATION_VARIABLE)) {
+ String location = (String) variables
+ .get(UIConstants.LOCATION_VARIABLE);
+ getPage().updateLocation(location);
}
}
public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";
@Deprecated
- public static final String FRAGMENT_VARIABLE = "fragment";
+ public static final String LOCATION_VARIABLE = "location";
@Deprecated
public static final String ATTRIBUTE_NOTIFICATION_STYLE = "style";
info += "<br />pathInfo: " + request.getRequestPathInfo();
info += "<br />parameters: " + request.getParameterMap().keySet();
info += "<br />uri fragment: "
- + request.getBrowserDetails().getUriFragment();
+ + request.getBrowserDetails().getLocation().getFragment();
return new Label(info, ContentMode.HTML);
}
@Override
protected void init(VaadinRequest request) {
Label label = new Label("Hello, your fragment is "
- + request.getBrowserDetails().getUriFragment());
+ + request.getBrowserDetails().getLocation().getFragment());
getContent().addComponent(label);
// React to fragment changes
});
// Handle the fragment received in the initial request
- handleFragment(request.getBrowserDetails().getUriFragment());
+ handleFragment(request.getBrowserDetails().getLocation().getFragment());
addComponent(new Button("Show and set fragment",
new Button.ClickListener() {
addComponent(log);
addComponent(naviLayout);
} catch (Exception e) {
- log.log("Exception: " + e.getMessage());
+ e.printStackTrace();
+ log.log("Exception: " + e);
}
}
}