-
-
Save tbroyer/1883821 to your computer and use it in GitHub Desktop.
/* | |
* Copyright 2012 Thomas Broyer <t.broyer@ltgt.net> | |
* | |
* 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 net.ltgt.gwt.place; | |
import com.google.gwt.event.logical.shared.HasValueChangeHandlers; | |
import com.google.gwt.event.logical.shared.ValueChangeEvent; | |
import com.google.gwt.event.logical.shared.ValueChangeHandler; | |
import com.google.gwt.event.shared.GwtEvent; | |
import com.google.gwt.event.shared.HandlerRegistration; | |
import com.google.gwt.event.shared.SimpleEventBus; | |
import com.google.gwt.place.shared.PlaceHistoryHandler.Historian; | |
/** | |
* An {@link Historian} using HTML5's {@code pushState} and {@code onpopstate}. | |
* <p> | |
* This code has only been tested in Firefox and Chrome, with | |
* {@link com.google.gwt.place.shared.PlaceHistoryHandler#handleCurrentHistory()} | |
* called from the {@link com.google.gwt.core.client.EntryPoint EntryPoint} (i.e. | |
* I don't know how it would work otherwise, wrt. Chrome firing an initial | |
* {@code popstate} event). | |
* | |
* @see https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history | |
* @see https://github.com/balupton/history.js/wiki/The-State-of-the-HTML5-History-API | |
*/ | |
public class Html5Historian implements Historian, | |
// allows the use of ValueChangeEvent.fire() | |
HasValueChangeHandlers<String> { | |
private final SimpleEventBus handlers = new SimpleEventBus(); | |
public Html5Historian() { | |
initEvent(); | |
} | |
@Override | |
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> valueChangeHandler) { | |
return this.handlers.addHandler(ValueChangeEvent.getType(), valueChangeHandler); | |
} | |
@Override | |
public String getToken() { | |
// your own logic here to extract the token from Window.Location | |
} | |
@Override | |
public void newItem(String token, boolean issueEvent) { | |
if (getToken().equals(token)) { // not sure if this is needed, but just in case | |
return; | |
} | |
// your own logic here to construct the new URI | |
pushState(newUri); | |
if (issueEvent) { | |
ValueChangeEvent.fire(this, getToken()); | |
} | |
} | |
@Override | |
public void fireEvent(GwtEvent<?> event) { | |
this.handlers.fireEvent(event); | |
} | |
private native void initEvent() /*-{ | |
var that = this; | |
var oldHandler = $wnd.onpopstate; | |
$wnd.onpopstate = $entry(function(e) { | |
that.@net.ltgt.gwt.place.Html5Historian::onPopState()(); | |
if (oldHandler) { | |
oldHandler(); | |
} | |
}); | |
}-*/; | |
private void onPopState() { | |
ValueChangeEvent.fire(this, getToken()); | |
} | |
private native void pushState(String url) /*-{ | |
$wnd.history.pushState(null, $doc.title, url); | |
}-*/; | |
} |
the link is not available :(
[UPDATE] https://github.com/carlos-aguayo/html5gwthistory this seems to be the new url ! :)
line 81: should be oldHandler(e);
article has moved here http://carlos-aguayo.github.io/html5/gwt/history/2012/08/29/html5-history-in-gwt.html
I am implementing this is in a web app, it works fine until I reload the page. I am using the Html5 historian from Carlos' repository. You can easily reproduce the issue by clicking on "Mail" in the app and reloading the page. The server says "Error not found". To be honest I really wonder how this could work in the first place. Surely the server would be serving the web app from the full path. I am missing something re the HTML5 history API? example URL http://gwthistoryhtml5.appspot.com/mail/
OK, I researched this a bit... it is incredibly messy, happy to hear suggestions on how to improve this.
- I added a (jetty) server side redirect using a filter. If the request URI contains my place tokens then I use the dispatcher to forward to the base servlet. The issue is this will apply to ANY resource I am requesting, eg images, javascript, etc... which also means they won't be cached anymore because from the client side it is seen as different resources each time I query from a different state.
- Another issue that crept in is that it messes up the GWT.getHostPageUrl() which seems to hard code the fact that navigation is done using # and queries... I had to rewrite my code which made use of this handy method to extract the real base URL.
- I had to rewite part of the historian to handle deeper URLs, ie the ones that have a base host URL with a path.
I am really not happy with the results, mostly because of 1) and I really wonder it is worth the hassle. Happy to hear people's opinion on this!
Complete example at http://carlosaguayo.posterous.com/html5-history-in-gwt courtesy of @carlos-aguayo