summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorMatti Tahvonen <matti@vaadin.com>2017-01-13 17:07:36 +0200
committerPekka Hyvönen <pekka@vaadin.com>2017-01-13 17:07:36 +0200
commit62c44dd77e47c908361a87332182f2e2465972c0 (patch)
tree2485171f3a1326d0f7bf0a067569e535dd18d626 /client
parentfe536b3efc4ed3d6637fead851c01375af91f762 (diff)
downloadvaadin-framework-62c44dd77e47c908361a87332182f2e2465972c0.tar.gz
vaadin-framework-62c44dd77e47c908361a87332182f2e2465972c0.zip
Support for HTML5 push/replaceState for proper deep linking features (#8116)
* Added support for HTML5 push/replaceState for proper deep linkin features * Automated test script now works at least on chrome * Uses html5 push/popstate to implement uri fragment feature * fire legacy fragment change events also via popstate events rpc calls * send new fragments via pushstate mechanism * formatting * Formatting and adding test and workaround for IE bug * Formatting and depracated UriFragmentListener * Aligned naming in the new API * Ignored IE due to web driver bug Tested a workaround with javascript based window.location.href fetch, but that don’t seem to work stable enough.
Diffstat (limited to 'client')
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VUI.java63
-rw-r--r--client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java68
-rwxr-xr-xclient/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml3
3 files changed, 39 insertions, 95 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VUI.java b/client/src/main/java/com/vaadin/client/ui/VUI.java
index ad4077d396..79c918f711 100644
--- a/client/src/main/java/com/vaadin/client/ui/VUI.java
+++ b/client/src/main/java/com/vaadin/client/ui/VUI.java
@@ -26,11 +26,7 @@ import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.logical.shared.HasResizeHandlers;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.http.client.URL;
-import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.SimplePanel;
@@ -46,7 +42,6 @@ import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.ApplicationConstants;
-import com.vaadin.shared.ui.ui.UIConstants;
/**
*
@@ -99,51 +94,8 @@ public class VUI extends SimplePanel implements ResizeHandler,
/** For internal use only. May be removed or replaced in the future. */
public boolean resizeLazy = false;
- private HandlerRegistration historyHandlerRegistration;
-
private TouchScrollHandler touchScrollHandler;
- /**
- * The current URI fragment, used to avoid sending updates if nothing has
- * changed.
- * <p>
- * For internal use only. May be removed or replaced in the future.
- */
- public String currentFragment;
-
- /**
- * Listener for URI fragment changes. Notifies the server of the new value
- * whenever the value changes.
- */
- private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
-
- @Override
- public void onValueChange(ValueChangeEvent<String> event) {
- String newFragment = event.getValue();
-
- // Send the location to the server if the fragment has changed
- // and flush active connectors in UI.
- if (!newFragment.equals(currentFragment) && connection != null) {
- /*
- * Ensure the fragment is properly encoded in all browsers
- * (#10769)
- *
- * createUrlBuilder does not properly pass an empty fragment to
- * UrlBuilder on Webkit browsers so do it manually (#11686)
- */
- String location = Window.Location.createUrlBuilder()
- .setHash(URL
- .decodeQueryString(Window.Location.getHash()))
- .buildString();
-
- currentFragment = newFragment;
- connection.flushActiveConnector();
- connection.updateVariable(id, UIConstants.LOCATION_VARIABLE,
- location, true);
- }
- }
- };
-
private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
new ScheduledCommand() {
@@ -186,21 +138,6 @@ public class VUI extends SimplePanel implements ResizeHandler,
}
}
- @Override
- protected void onAttach() {
- super.onAttach();
- historyHandlerRegistration = History
- .addValueChangeHandler(historyChangeHandler);
- currentFragment = History.getToken();
- }
-
- @Override
- protected void onDetach() {
- super.onDetach();
- historyHandlerRegistration.removeHandler();
- historyHandlerRegistration = null;
- }
-
/**
* Stop monitoring for parent element resizes.
*/
diff --git a/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java b/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
index 180898453b..49475901c9 100644
--- a/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
@@ -43,18 +43,17 @@ import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent;
+import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.Focusable;
@@ -105,6 +104,8 @@ import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.UI;
+import elemental.client.Browser;
+
@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
public class UIConnector extends AbstractSingleComponentContainerConnector
implements Paintable, MayScrollChildren {
@@ -115,6 +116,12 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
private HandlerRegistration windowOrderRegistration;
+ /*
+ * Used to workaround IE bug related to popstate events and certain fragment
+ * only changes
+ */
+ private String currentLocation;
+
private final StateChangeHandler childStateChangeHandler = new StateChangeHandler() {
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
@@ -232,6 +239,28 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
}
});
+
+ Browser.getWindow().setOnpopstate(evt -> {
+ final String newLocation = Browser.getWindow().getLocation()
+ .toString();
+ getRpcProxy(UIServerRpc.class).popstate(newLocation);
+ currentLocation = newLocation;
+ });
+ // IE doesn't fire popstate correctly with certain hash changes.
+ // Simulate the missing event with History handler.
+ if (BrowserInfo.get().isIE()) {
+ History.addValueChangeHandler(evt -> {
+ final String newLocation = Browser.getWindow().getLocation()
+ .toString();
+ if (!newLocation.equals(currentLocation)) {
+ currentLocation = newLocation;
+ getRpcProxy(UIServerRpc.class).popstate(
+ Browser.getWindow().getLocation().toString());
+ }
+ });
+ currentLocation = Browser.getWindow().getLocation().toString();
+ }
+
}
private native void open(String url, String name)
@@ -402,34 +431,13 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
scrollIntoView(connector);
}
- if (uidl.hasAttribute(UIConstants.LOCATION_VARIABLE)) {
- String location = uidl
- .getStringAttribute(UIConstants.LOCATION_VARIABLE);
- String newFragment;
-
- int fragmentIndex = location.indexOf('#');
- if (fragmentIndex >= 0) {
- // Decode fragment to avoid double encoding (#10769)
- newFragment = URL.decodePathSegment(
- location.substring(fragmentIndex + 1));
-
- if (newFragment.isEmpty()
- && Location.getHref().indexOf('#') == -1) {
- // Ensure there is a trailing # even though History and
- // Location.getHash() treat null and "" the same way.
- Location.assign(Location.getHref() + "#");
- }
- } else {
- // No fragment in server-side location, but can't completely
- // remove the browser fragment since that would reload the page
- newFragment = "";
- }
-
- getWidget().currentFragment = newFragment;
-
- if (!newFragment.equals(History.getToken())) {
- History.newItem(newFragment, true);
- }
+ if (uidl.hasAttribute(UIConstants.ATTRIBUTE_PUSH_STATE)) {
+ Browser.getWindow().getHistory().pushState(null, "",
+ uidl.getStringAttribute(UIConstants.ATTRIBUTE_PUSH_STATE));
+ }
+ if (uidl.hasAttribute(UIConstants.ATTRIBUTE_REPLACE_STATE)) {
+ Browser.getWindow().getHistory().replaceState(null, "", uidl
+ .getStringAttribute(UIConstants.ATTRIBUTE_REPLACE_STATE));
}
if (firstPaint) {
diff --git a/client/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml b/client/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml
index ad345e44e2..477ec43288 100755
--- a/client/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml
+++ b/client/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml
@@ -8,8 +8,7 @@
<inherits name="com.vaadin.Vaadin" />
- <!-- Elemental is used for handling Json only -->
- <inherits name="elemental.Json" />
+ <inherits name="elemental.Elemental" />
<inherits name="com.google.gwt.precompress.Precompress" />