Skip to content

Instantly share code, notes, and snippets.

@jroper
Created May 7, 2012 12:32
Show Gist options
  • Save jroper/2627517 to your computer and use it in GitHub Desktop.
Save jroper/2627517 to your computer and use it in GitHub Desktop.
GWTP HTML5 pushState place manager implementation
package com.gwtplatform.mvp.client.proxy;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.user.client.Window;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
@Singleton
public class Html5PushStatePlaceManager extends PlaceManagerImpl {
@Inject
public Html5PushStatePlaceManager(
final EventBus eventBus,
final TokenFormatter tokenFormatter) {
super(eventBus, tokenFormatter);
}
private String getGwtCodesvr() {
return Window.Location.getParameter("gwt.codesvr");
}
@Override
void setBrowserHistoryToken(String historyToken, boolean issueEvent) {
// Need to ensure we don't accidentally leave development mode
String path = historyToken;
String gwtCodesvr = getGwtCodesvr();
if (gwtCodesvr != null) {
if (path.contains("?")) {
path += "&";
} else {
path += "?";
}
path += "gwt.codesvr=" + gwtCodesvr;
}
pushState(path, historyToken);
}
/**
* Push the state using HTML5 push state. This method will fallback to doing a page refresh style load if HTML5
* pushState is not available.
*
* @param path The path to push
* @param historyToken The history token to load if the back/forward buttons are used
* @return True if pushState was available and it succeeded, otherwise false.
*/
private native boolean pushState(String path, String historyToken) /*-{
var state = {historyToken:historyToken};
if ($wnd.history && $wnd.history.pushState) {
var length = $wnd.history.length;
$wnd.history.pushState(state, null, path);
if (length != $wnd.history.length) {
return true;
} else {
// If the history length hasn't changed, then pushState mustn't be enabled. Fall back to $wnd.location.
$wnd.location = path;
return false;
}
} else {
$wnd.location = path;
return false;
}
}-*/;
/**
* Overridden so that it returns the path (and query string) rather than everything after the hash.
*
* @return The history token
*/
@Override
String getBrowserHistoryToken() {
String historyToken = Window.Location.getPath();
// Get the query string, but exclude the gwt.codesvr parameter if it exists
String queryString = Window.Location.getQueryString();
if (queryString != null) {
queryString = queryString.replaceAll("gwt\\.codesvr=[^&]*", "");
if (!queryString.trim().isEmpty() && !queryString.equals("?")) {
historyToken += queryString;
}
}
return historyToken;
}
/**
* Overridden so that rather than registering a GWT history handler, registers an HTML5 popState handler.
*/
@Override
void registerTowardsHistory() {
registerPopStateHandler();
}
/**
* Register a handler for pop state. If one already exists, it will be called after this one does its thing.
*/
private native void registerPopStateHandler() /*-{
var placeManager = this;
var oldHandler = $wnd.onpopstate;
$wnd.onpopstate = $entry(function (event) {
if (event.state && event.state.historyToken) {
placeManager.@com.gwtplatform.mvp.client.proxy.Html5PushStatePlaceManager::onPopState(Ljava/lang/String;)(event.state.historyToken);
}
if (oldHandler) {
oldHandler(event);
}
});
}-*/;
/**
* Called by native code when someone pushes the back/forward button.
*
* @param historyToken The history token that has been navigated to
*/
void onPopState(String historyToken) {
onValueChange(new ValueChangeEvent<String>(historyToken) {
});
}
/**
* Overridden so that it doesn't go through the GWT history stuff
*/
@Override
public void revealCurrentPlace() {
onValueChange(new ValueChangeEvent<String>(getBrowserHistoryToken()) {
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment