diff options
author | Matti Tahvonen <matti@vaadin.com> | 2017-01-13 17:07:36 +0200 |
---|---|---|
committer | Pekka Hyvönen <pekka@vaadin.com> | 2017-01-13 17:07:36 +0200 |
commit | 62c44dd77e47c908361a87332182f2e2465972c0 (patch) | |
tree | 2485171f3a1326d0f7bf0a067569e535dd18d626 /client | |
parent | fe536b3efc4ed3d6637fead851c01375af91f762 (diff) | |
download | vaadin-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')
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" /> |