com.wallissoftware.pushstate.client.PushStateHistorianImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.wallissoftware.pushstate.client.PushStateHistorianImpl.java

Source

/*
 * Copyright 2014 Richard Wallis
 * 
 * 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 com.wallissoftware.pushstate.client;

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.EventBus;
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;
import com.google.gwt.user.client.Window;

public class PushStateHistorianImpl implements Historian, HasValueChangeHandlers<String> {

    private final EventBus handlers = new SimpleEventBus();
    private String token;
    private final String relativePath;

    PushStateHistorianImpl(String relativePath) {
        relativePath = relativePath.startsWith("/") ? relativePath : "/" + relativePath;
        relativePath = relativePath.endsWith("/") ? relativePath : relativePath + "/";
        this.relativePath = relativePath;
        initToken();
        registerPopstateHandler();
    }

    @Override
    public String getToken() {
        return token;
    }

    @Override
    public void newItem(String token, boolean issueEvent) {
        newItem(token, issueEvent, false);
    }

    @Override
    public void fireEvent(GwtEvent<?> event) {
        this.handlers.fireEvent(event);
    }

    private native void registerPopstateHandler()/*-{
                                                 var that = this;
                                                 var oldHandler = $wnd.onpopstate;
                                                 $wnd.onpopstate = $entry(function(e) {
                                                 that.@com.wallissoftware.pushstate.client.PushStateHistorianImpl::onPopState(Ljava/lang/String;)(e.state.token);
                                                 if (oldHandler) {
                                                 oldHandler(e);
                                                 }
                                                 });
                                                 }-*/;

    private void onPopState(String token) {
        if (setToken(token)) {
            ValueChangeEvent.fire(this, getToken());
        }
    }

    private void initToken() {
        String token = Window.Location.getPath() + Window.Location.getQueryString();

        setToken(token);
        replaceState(relativePath, getToken());
    }

    private String stripStartSlash(String input) {
        return input.startsWith("/") ? input.substring(1) : input;
    }

    private String stripRelativePath(String token) {
        String relPath = stripStartSlash(relativePath);
        token = stripStartSlash(token);

        if (token.startsWith(relPath)) {
            return stripStartSlash(token.substring(relPath.length()));
        }
        return token;
    }

    private static native void replaceState(final String relativePath, final String token) /*-{
                                                                                           $wnd.history.replaceState({'token':token}, $doc.title, relativePath + token);
                                                                                           }-*/;

    private static native void pushState(final String relativePath, final String token) /*-{
                                                                                        $wnd.history.pushState({'token':token}, $doc.title,  relativePath + token);
                                                                                        }-*/;

    private boolean setToken(String newToken) {
        newToken = stripRelativePath(newToken);
        if (!matchesToken(newToken)) {
            token = newToken;
            return true;
        }
        return false;
    }

    private boolean matchesToken(String compare) {
        return token != null
                && (compare.equals(token) || compare.equals(token + "/") || token.equals(compare + "/"));
    }

    @Override
    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> valueChangeHandler) {
        return this.handlers.addHandler(ValueChangeEvent.getType(), valueChangeHandler);
    }

    public void newItem(String token, boolean issueEvent, boolean replaceState) {
        if (setToken(token)) {
            if (replaceState) {
                replaceState(relativePath, getToken());
            } else {
                pushState(relativePath, getToken());
            }

            if (issueEvent) {
                ValueChangeEvent.fire(this, getToken());
            }
        }

    }
}