Package com.google.livingstories.client.util

Source Code of com.google.livingstories.client.util.HistoryManager$HistoryChangeHandler

/**
* Copyright 2010 Google Inc.
*
* 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.google.livingstories.client.util;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.livingstories.client.FilterSpec;
import com.google.livingstories.client.lsp.Page;
import com.google.livingstories.client.lsp.Page.LoadHandler;
import com.google.livingstories.client.lsp.views.PlayerPage;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/**
* Class that manages history tokens and navigation.
*
* Note that we use Window.Location.getHash() to get the history token everywhere
* in this class, rather than History.getToken().  We do this because IE has issues
* with firing history change events when the hash is updated programmatically, which
* causes History.getToken to return out of date results.
*/
public class HistoryManager {
  public enum HistoryPages {
    OVERVIEW {
      @Override
      public Page getPage(String[] tokens) {
        return PageCache.getOverviewPage(new FilterSpec(tokens[1]),
            tokens[2].equals("null") ? null : Long.valueOf(tokens[2]));
      }
      @Override
      public String createToken(String... params) {
        // name:filterParams:focusedContentItemId (for filterParams see FilterSpec.java)
        return name() + ":" + params[0] + ":" + params[1];
      }
      @Override
      public Map<String, String> getDefaultState() {
        return new HashMap<String, String>();
      }
    },
    PLAYER {
      @Override
      public Page getPage(String[] tokens) {
        PlayerPage playerPage = new PlayerPage();
        playerPage.load(Long.valueOf(tokens[1]));
        return playerPage;
      }
      @Override
      public String createToken(String... params) {
        // name:contentItemId
        return name() + ":" + params[0];
      }
      @Override
      public Map<String, String> getDefaultState() {
        return new HashMap<String, String>();
      }
    };
   
    public abstract Page getPage(String[] pageTokens);
   
    public abstract String createToken(String... params);
   
    public abstract Map<String, String> getDefaultState();
  }
 
  public static class HistoryChangeHandler implements ValueChangeHandler<String> {
    @Override
    public void onValueChange(ValueChangeEvent<String> e) {
      if (e.getValue().isEmpty()) {
        // Handles the case where the history token is empty (e.g. first visit)
        loadMainPage();
        return;
      }
      final String[] newTokens = e.getValue().split(";");
      String newPageToken = newTokens[0];
      if (page == null || !pageToken.equals(newPageToken)) {
        pageToken = newPageToken;
        String[] pageParams = newPageToken.split(":");
        HistoryPages historyPage = HistoryPages.valueOf(pageParams[0]);
        Page newPage = historyPage.getPage(pageParams);
        pageState = historyPage.getDefaultState();
        if (newPage != page) {
          page = newPage;
          LivingStoryControls.goToPage(page);
        }
      }
      changeState(newTokens);
      if (page.isLoaded()) {
        page.onShow();
        executeState();
      } else {
        page.addLoadHandler(new LoadHandler() {
          public void onLoad() {
            page.onShow();
            executeState();
          }
        });
      }
    }
   
    private void changeState(String[] tokens) {
      pageState.clear();
      for (int i = 1; i < tokens.length; i++) {
        String[] state = tokens[i].split(":");
        pageState.put(state[0], state[1]);
      }
    }
   
    private void executeState() {
      // Prevent state change operations from setting extra tokens
      beginBatchStateChange();
      for (Entry<String, String> state : pageState.entrySet()) {
        page.changeState(state.getKey(), state.getValue());
      }
      endBatchStateChange();
    }
  }

  private static HistoryChangeHandler historyChangeHandler;
  private static String pageToken;
  private static Page page;
  private static Map<String, String> pageState;
  private static boolean batchStateChange = false;
  private static boolean initialized = false;

  /**
   * Convenience method for creating a new history page with the default state.
   * This method is a hack to let the player page transition work properly.
   */
  public static void newToken(Page page, HistoryPages historyPage, String... params) {
    HistoryManager.page = page;
    pageToken = historyPage.createToken(params);
    pageState = historyPage.getDefaultState();
    setToken();
  }

  /**
   * Convenience method for updating the pageToken without changing the page.
   */
  public static void newToken(HistoryPages historyPage, String... params) {
    pageToken = historyPage.createToken(params);
    pageState = historyPage.getDefaultState();
    setToken();
  }

  /**
   * Convenience method for creating a new history page with the default state and
   * firing a history changed event.
   */
  public static void newTokenWithEvent(HistoryPages page, String... params) {
    String token = page.createToken(params) + ";";
    if (!token.equals(getHash())) {
      History.newItem(token);
    }
  }
 
  /**
   * Sets a single state key/value pair without changing the current page.
   * Pass in a null as the state value to unset a key.
   */
  public static void changeState(String key, String value) {
    if (value == null) {
      if (value != pageState.remove(key)) {
        setToken();
      }
    } else {
      if (!value.equals(pageState.put(key, value))) {
        setToken();
      }
    }
  }
 
  public static void beginBatchStateChange() {
    batchStateChange = true;
  }

  public static void endBatchStateChange() {
    batchStateChange = false;
    setToken();
  }

  public static String getState(String key) {
    return pageState.get(key);
  }
 
  public static String getLink(HistoryPages page, String... params) {
    String href = Window.Location.getHref().split("#")[0];
    return href.concat("#" + getToken(page.createToken(params), page.getDefaultState()));
  }
 
  public static String getTokenStringForFocusedContentItem(Long focusedContentItemId) {
    return "#" + HistoryPages.OVERVIEW.createToken(
        getDefaultFilterSpec().getFilterParams(), focusedContentItemId.toString())
        + ";";
  }
 
  private static String getToken(String pageToken, Map<String, String> pageState) {
    StringBuilder sb = new StringBuilder(pageToken).append(";");
    for (Entry<String, String> entry : pageState.entrySet()) {
      sb.append(entry.getKey()).append(":").append(entry.getValue()).append(";");
    }
    return sb.toString();   
  }
 
  private static void setToken() {
    if (batchStateChange) {
      return;
    }
    String token = getToken(pageToken, pageState);
    if (!token.equals(getHash())) {
      History.newItem(token, false);
    }
  }
 
  private static String getHash() {
    // In IE, we need to use the location.hash value, since it doesn't fire history
    // change events properly so that History.getToken returns the right value.
    // In chrome, we can't use location.hash because THAT doesn't return the right value,
    // apparently.
    return isIE() ? Window.Location.getHash().replaceAll("#", "") : History.getToken();
  }
 
  public static void loadMainPage() {
    String currentUrl = Window.Location.getHref().split("#")[0];
    final String token = HistoryPages.OVERVIEW.createToken(
        getDefaultFilterSpec().getFilterParams(), null) + ";";
    Window.Location.replace(currentUrl + "#" + token);
    Command fireValueChange = new Command() {
      @Override
      public void execute() {
        historyChangeHandler.onValueChange(new ValueChangeEvent<String>(token){});
      }
    };
    if (isIE()) {
      // In IE, we need to fire this immediately or we get into an infinite redirect loop.
      fireValueChange.execute();
    } else {
      // In chrome, we need to delay this, otherwise getHash() doesn't return the right value.
      DeferredCommand.addCommand(fireValueChange);
    }
  }
 
  private static FilterSpec getDefaultFilterSpec() {
    String defaultPageParams = LivingStoryData.getDefaultPage();
    return (defaultPageParams == null || defaultPageParams.isEmpty())  ?
        new FilterSpec() : new FilterSpec(defaultPageParams);
  }
 
  public static void initialize() {
    historyChangeHandler = new HistoryManager.HistoryChangeHandler();
    History.addValueChangeHandler(historyChangeHandler);
    if (getHash().isEmpty()) {
      loadMainPage();
    } else {
      History.fireCurrentHistoryState();
    }
    initialized = true;
  }
 
  public static boolean isInitialized() {
    return initialized;
  }
 
  private static native boolean isIE() /*-{
    return $wnd.navigator.appName == "Microsoft Internet Explorer";
  }-*/;
TOP

Related Classes of com.google.livingstories.client.util.HistoryManager$HistoryChangeHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.