Load all internal link by using ajax
diff --git a/src/main/java/com/google/gwt/site/webapp/client/GWTProjectEntryPoint.java b/src/main/java/com/google/gwt/site/webapp/client/GWTProjectEntryPoint.java
index 0dd1120..dcf04a7 100644
--- a/src/main/java/com/google/gwt/site/webapp/client/GWTProjectEntryPoint.java
+++ b/src/main/java/com/google/gwt/site/webapp/client/GWTProjectEntryPoint.java
@@ -19,29 +19,48 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.query.client.Function;
 import com.google.gwt.query.client.GQuery;
+import com.google.gwt.regexp.shared.RegExp;
+import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Window;
 
 import static com.google.gwt.query.client.GQuery.$;
+import static com.google.gwt.query.client.GQuery.body;
 
 public class GWTProjectEntryPoint implements EntryPoint {
-	private String currentPage;
+  private static final RegExp INTERNAL_URL_REGEX;
+  private static final RegExp NOT_RELATIVE_URL_REGEX;
+
+  static {
+    String domainUrl =  Window.Location.getHostName();
+    String port = Window.Location.getPort();
+
+    if (port != null && port.length() > 0) {
+      domainUrl += ":" + port;
+    }
+
+    INTERNAL_URL_REGEX = RegExp.compile("^(https?)\\:\\/\\/" + domainUrl + "\\/.*$");
+    NOT_RELATIVE_URL_REGEX = RegExp.compile("^(https?)|(mailto)|(ftp)|(javascript)\\:.*$");
+  }
+
+
+  private String currentPage;
 
 	@Override
 	public void onModuleLoad() {	
 		enhanceMenu();
     
-    openMenu();
+    openMenu(Window.Location.getPath());
 
     if (supportsHtml5History()) {
       initOnPopState();
     }
 	}
 
-  private void openMenu() {
-    String href = Window.Location.getPath();
+  private void openMenu(String path) {
+    $("#gwt-toc a.selected").removeClass("selected");
 
-    if (href != null && href.length() > 0) {
-      $("#gwt-toc a[href$='" + href + "']").addClass("selected")
+    if (path != null && path.length() > 0) {
+      $("#gwt-toc a[href$='" + path + "']").addClass("selected")
           .parentsUntil("#gwt-toc").filter("li.folder").addClass("open")
           .children("ul").slideDown(200);
     }
@@ -58,17 +77,25 @@
 		
 		$("#gwt-toc li.folder > ul").css("display", "none");
 
-		$("#gwt-toc a").click(new Function() {
+    $("a", body).live(Event.ONCLICK, new Function() {
       @Override
-      public void f(Element e) {
-        loadPage(e.getAttribute("href"), true);
+      public boolean f(Event event) {
+        String href = getElement().getAttribute("href");
 
-        selectItem(e);
+        if (isInternalNavigation(href)) {
+          return loadPage(href, true);
+        }
 
-        getEvent().preventDefault();
+        return true;
       }
     });
-	}
+  }
+
+  private boolean isInternalNavigation(String href) {
+    // TODO mix the three last conditions in one regex !!
+    return href != null && href.length() > 0 && (!href.startsWith("#") && !NOT_RELATIVE_URL_REGEX.test(href)
+        || INTERNAL_URL_REGEX.test(href));
+  }
 
 	private void toggleMenu(GQuery menu) {
 		if (menu.hasClass("open")) {
@@ -80,35 +107,45 @@
 		menu.children("ul").slideToggle(200);
 	}
 
-	private void loadPage(String pageUrl, boolean pushState) {
-		if (pageUrl.equals(currentPage)) {
-			return;
-		}
+  private boolean loadPage(final String pageUrl, final boolean pushState) {
+    int hashIndex = pageUrl.indexOf('#');
+    final String path = hashIndex != -1 ? pageUrl.substring(0, hashIndex) : pageUrl;
+    final String hash = hashIndex != -1 ? pageUrl.substring(hashIndex) : null;
 
-		if (supportsHtml5History()) {
-			currentPage = pageUrl;
-			
+    if (supportsHtml5History() && !path.equals(currentPage)) {
+      currentPage = path;
 
-			$("#gwt-content").load(pageUrl + " #gwt-content > div");
 
-      if (pushState) {
-			  pushState(pageUrl);
-      }
+      $("#gwt-content").load(pageUrl + " #gwt-content > div", null, new Function(){
+          @Override
+          public void f() {
+            if (pushState) {
+              pushState(pageUrl);
+            }
+            if (hash != null) {
+              scrollTo(hash);
+            }
+            openMenu(path);
+          }
+        }
+      );
 
-    } else {
-      Window.Location.replace(pageUrl);
+      return false;
+    } else if (hash != null) {
+      scrollTo(hash);
     }
-	}
+
+    return !path.equals(currentPage);
+  }
+
+  private void scrollTo(String hash) {
+    Window.scrollTo(Window.getScrollLeft(), $(hash).offset().top);
+  }
 
   private void onPopState() {
     loadPage(Window.Location.getPath(), false);
   }
 
-  private void selectItem(Element item) {
-    $("#gwt-toc a.selected").removeClass("selected");
-    item.addClassName("selected");
-  }
-
 	private native boolean pushState(String url) /*-{
 		$wnd.history.pushState(null, null, url);
 	}-*/;