Package com.google.silvercomet.client

Source Code of com.google.silvercomet.client.Main$Resources

package com.google.silvercomet.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;

import elemental.client.Browser;
import elemental.css.CSSStyleDeclaration;
import elemental.css.CSSStyleDeclaration.Display;
import elemental.css.CSSStyleDeclaration.Unit;
import elemental.css.CSSStyleDeclaration.Visibility;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.events.KeyboardEvent;
import elemental.dom.Document;
import elemental.dom.Element;
import elemental.html.InputElement;
import elemental.html.StyleElement;
import elemental.util.ArrayOf;
import elemental.util.ArrayOfInt;
import elemental.util.Collections;
import elemental.dom.*;

/**
* All the view code that is fit to run.
*
* @author knorton@google.com (Kelly Norton)
*/
public class Main implements EntryPoint, Model.Listener, EventListener {

  /**
   * Access to all the relevant classnames and constants for the CSS selectors.
   */
  public static interface Css extends CssResource {
    String bar();

    String browserInfo();

    String count();

    String label();

    String marker();

    String moreResults();

    String result();

    String resultLeft();

    String resultName();

    String resultRight();

    String root();

    int rootHeight();

    int rootWidth();

    String tickMajor();

    String tickMinor();
  }

  /**
   * Bundles the CSS resources.
   */
  public interface Resources extends ClientBundle {
    @Source("silver-comet.gwt.css")
    Css css();
  }

  /**
   * A simple view to show a runner's finishing info.
   */
  private static class RunnerView {
    /**
     * Returns a string describing a runner's place & finishing time. Example:
     * 325th (1:49:11)
     */
    private static String infoString(Runner runner) {
      return placeString(runner.place()) + " (" + secondsToTime(runner.time(), true) + ")";
    }

    /**
     * Produces a english locale human readable places. Example: 1st, 2nd, 11th,
     * etc.
     */
    private static String placeString(int place) {
      final int tens = place / 10;
      final int ones = place % 10;
      if (ones == 1 && tens != 1) {
        return place + "st";
      } else if (ones == 2 && tens != 1) {
        return place + "nd";
      } else if (ones == 3 && tens != 1) {
        return place + "rd";
      } else {
        return place + "th";
      }
    }

    /**
     * Sets the current runner being displayed.
     */
    private static native void setRunner(Element element, Runner runner) /*-{
      element.currentRunner = runner;
    }-*/;

    /**
     * This is a hack for sure, but I claim it demonstrates your ability to
     * commit clever atrosities in JavaScript even while working in Java.
     */
    static native Runner getRunnerFromElement(Element element) /*-{
      return element.currentRunner || element.parentNode.currentRunner;
    }-*/;

    private final Element root;

    private final Element name;

    private final Element info;

    private final double secondsPerPixel;

    /**
     * Create a new view with a classname for the root element and a scaling
     * factor for translating along the timeline.
     */
    RunnerView(String rootClass, double secondsPerPixel) {
      this(rootClass, null, secondsPerPixel);
    }

    /**
     * Create a new view classnames for the root element and text elements and a
     * scaling factor for translating along the timeline.
     */
    RunnerView(String rootClass, String textClass, double secondsPerPixel) {
      root = div(rootClass);
      name = textClass == null ? div() : div(textClass);
      info = textClass == null ? div() : div(textClass);

      root.appendChild(name);
      root.appendChild(info);

      this.secondsPerPixel = secondsPerPixel;
    }

    /**
     * Returns the root element for the view. Generally used to add the view to
     * the DOM.
     */
    Element element() {
      return root;
    }

    /**
     * Make the view invisible.
     */
    void hide() {
      root.getStyle().setVisibility(Visibility.HIDDEN);
    }

    /**
     * Make the view visible.
     */
    void show() {
      root.getStyle().removeProperty("visibility");
    }

    /**
     * Update the view to show the info of a runner.
     */
    void update(Runner runner) {
      setRunner(root, runner);
      name.setTextContent(runner.name());
      info.setTextContent(infoString(runner));
      final int x = (int) ((double) runner.time() / (double) Model.SECONDS_PER_HISTOGRAM_BUCKET
          * secondsPerPixel);

      // TODO(knorton): This is actually wrong because it sets left on all
      // markers.
      root.getStyle().setLeft(x, Unit.PX);
      show();
    }
  }

  private static final int NUM_SEARCH_RESULTS = 6;

  /*
   * Get the correct classname based on the index of the result. This allows for
   * different classnames on the first and last item.
   */
  private static String cssClassForResultItem(Css css, int index) {
    if (index == 0) {
      return css.result() + " " + css.resultLeft();
    }

    if (index == NUM_SEARCH_RESULTS - 1) {
      return css.result() + " " + css.resultRight();
    }

    return css.result();
  }

  /**
   * Convenience method for creating a new div.
   */
  private static Element div() {
    return Browser.getDocument().createElement("div");
  }

  /**
   * Convenience method for creating a new div with a classname.
   */
  private static Element div(String className) {
    final Element e = div();
    e.setClassName(className);
    return e;
  }

  private static String getBrowserInfoString() {
    final Browser.Info info = Browser.getInfo();
    if (info.isWebKit()) {
      return "WebKit Browser";
    } else if (info.isGecko()) {
      return "Gecko Browser";
    }
    return "Unsupported Browser";
  }

  private static void injectStyles(Document document, String css) {
    final StyleElement style = (StyleElement)document.createElement("style");
    style.setTextContent(css);
    document.getHead().appendChild(style);
  }

  /**
   * Converts a integer to a {@link String}, prepending a zero if the string
   * representation is only 1 character in length.
   */
  private static String pad(int number) {
    return number > 9 ? "" + number : "0" + number;
  }

  /**
   * Converts the number of seconds to a more human readable finishing time.
   */
  private static String secondsToTime(int seconds, boolean includeSeconds) {
    final int hrs = seconds / 3600;
    final int mns = seconds / 60 - hrs * 60;
    if (includeSeconds) {
      final int scs = seconds - hrs * 3600 - mns * 60;
      return hrs + ":" + pad(mns) + ":" + pad(scs);
    }
    return hrs + ":" + pad(mns);
  }

  private final Css css = GWT.<Resources>create(Resources.class).css();

  private Element root;

  private InputElement search;

  private RunnerView marker;

  private Model model;

  private String lastQuery;

  private Element results;

  private ArrayOf<RunnerView> resultItems;

  private double xAxisScale;

  private Element moreResults;

  /**
   * Handles all DOM events for the app.
   */
  @Override
  public void handleEvent(Event evt) {
    final Element target = (Element) evt.getTarget();

    // Handle searches.
    if (target == search) {
  //      if (((KeyboardEvent)evt).getKeyCode() == 42) {
  //        clearSearch();
  //      } else {
        final String query = search.getValue();
        updateSearch(query == null ? "" : query.trim());
  //      }
      return;
    }

    // Handle clicks on search results.
    final Runner runner = RunnerView.getRunnerFromElement(target);
    if (runner != null) {
      marker.update(runner);
      clearSearch();
      return;
    }
  }

  /**
   * Indicates that the data failed to load.
   */
  @Override
  public void modelDidFailLoading(Model model) {
  }

  /**
   * Indicates that the model finished building the search indexes.
   */
  @Override
  public void modelDidFinishBuildingIndex(Model model) {
    // TODO(knorton): File crbug about readOnly not working properly.
    // search.setReadOnly(false);
    search.focus();
  }

  /**
   * Indicates that all data has been loaded into the model.
   */
  @Override
  public void modelDidFinishLoading(Model model) {
    final ArrayOfInt histogram = model.histogram();
    assert histogram.length() > 0 : "histogram is empty.";

    xAxisScale = (double) css.rootWidth() / (double) histogram.length();

    // Build the histogram graph.
    render();

    // Create the marker.
    marker = new RunnerView(css.marker(), xAxisScale);
    marker.hide();
    root.appendChild(marker.element());
    Browser.getDocument().getBody().getStyle().setOpacity(1.0);
  }

  /**
   * The main entry point for the application.
   */
  public void onModuleLoad() {
    injectStyles(Browser.getDocument(), css.getText());

    // TODO(knorton): Bad Elemental pattern.
    search = (InputElement) Browser.getDocument().getElementById("search");
    // TODO(knorton): File crbug about readOnly not working properly.
    // search.setReadOnly(true);
    search.addEventListener("change", this, false);
    search.addEventListener("keyup", this, false);
    search.addEventListener("keydown", this, false);

    root = (Element) Browser.getDocument().getElementById("c");
    root.setClassName(css.root());

    results = (Element)Browser.getDocument().getElementById("r");
    results.getStyle().setVisibility(Visibility.HIDDEN);
    results.addEventListener("click", this, false);

    // Browser info indicator.
    // TODO(knorton): Put this in a debug perm.
    final Element info = Browser.getDocument().getElementById("f");
    info.setClassName(css.browserInfo());
    info.setTextContent(getBrowserInfoString());
   
    model = new Model(this);
    model.load();
  }

  /**
   * Clear the search box and hide the result item list.
   */
  private void clearSearch() {
    search.setValue("");
    hideSearchResults();
  }

  /**
   * Ensure that the DOM for result items has been built and appended to the
   * DOM.
   */
  private void ensureSearchResultItems() {
    if (resultItems != null) {
      return;
    }

    resultItems = Collections.arrayOf();
    for (int i = 0; i < NUM_SEARCH_RESULTS; ++i) {
      final RunnerView marker =
          new RunnerView(cssClassForResultItem(css, i), css.resultName(), xAxisScale);
      results.appendChild(marker.element());
      resultItems.push(marker);
    }

    moreResults = div(css.moreResults());
    results.appendChild(moreResults);
    moreResults.getStyle().setDisplay(Display.NONE);
  }
 
  /**
   * Hide the search result items list.
   */
  private void hideSearchResults() {
    results.getStyle().setVisibility(Visibility.HIDDEN);
  }

  /**
   * Renders the bar graph.
   */
  private void render() {
    final ArrayOfInt histogram = model.histogram();

    final int padding = 2;
    final int topPadding = 50;

    final double dx = xAxisScale;
    final double dy = (double) css.rootHeight() / histogram.get(histogram.length() - 1);
    final double halfDx = dx / 2.0;

    // Render all bars.
    for (int i = 0, n = histogram.length(); i < n; ++i) {
      final int value = histogram.get(i);
      if (value == 0) continue;

      final int x = (int) (dx * i) + padding;
      final int h = (int) (dy * value) - topPadding;
      final int w = (int) dx - padding * 2;

      // Create the vertical bar.
      final Element bar = div(css.bar());
      final CSSStyleDeclaration barStyle = bar.getStyle();
      barStyle.setLeft(x, Unit.PX);
      barStyle.setBottom("0");
      barStyle.setHeight(h, Unit.PX);
      barStyle.setWidth(w, Unit.PX);

      // Add a count at the top.
      final Element count = div(css.count());
      count.setTextContent("" + value);

      bar.appendChild(count);
      root.appendChild(bar);
    }

    // Render labels
    for (int i = 0, n = histogram.length(); i <= n; ++i) {
      final int x = (int) (dx * i);
      final int w = (int) dx;

      final String time = secondsToTime(i * Model.SECONDS_PER_HISTOGRAM_BUCKET, false);

      final Element label = div(css.label());
      label.setTextContent(time);
      final CSSStyleDeclaration labelStyle = label.getStyle();
      labelStyle.setLeft(x - dx, Unit.PX);
      labelStyle.setWidth(w, Unit.PX);
      root.appendChild(label);

      // TODO(knorton): Heh, that's pretty trashy. I should fix that. :-)
      final Element tick =
          div(time.charAt(time.length() - 1) == '0' && time.charAt(time.length() - 2) == '0'
              ? css.tickMajor() : css.tickMinor());
      tick.getStyle().setLeft(x, Unit.PX);
      root.appendChild(tick);
    }
  }

  /**
   * Show the search result items list and update it with the specified list of
   * results.
   */
  private void showSearchResults(ArrayOf<Runner> runners) {
    ensureSearchResultItems();
    results.getStyle().removeProperty("visibility");
    for (int i = 0; i < NUM_SEARCH_RESULTS; ++i) {
      final RunnerView item = resultItems.get(i);
      if (i < runners.length()) {
        item.show();
        item.update(runners.get(i));
      } else {
        item.hide();
      }
    }

    if (runners.length() > NUM_SEARCH_RESULTS) {
      moreResults.setTextContent("+" + (runners.length() - NUM_SEARCH_RESULTS) + " more");
      moreResults.getStyle().removeProperty("display");
    } else {
      moreResults.getStyle().setDisplay(Display.NONE);
    }
  }

  /**
   * Update the search results visually for the specified query.
   */
  private void updateSearch(String query) {
    if (query.equals(lastQuery)) {
      return;
    }

    lastQuery = query;
    if (query.length() == 0) {
      hideSearchResults();
    }

    final ArrayOf<Runner> runners = model.search(query);
    if (runners == null) {
      hideSearchResults();
    } else if (runners.length() == 1) {
      hideSearchResults();
      marker.update(runners.get(0));
    } else {
      showSearchResults(runners);
    }
  }
}
TOP

Related Classes of com.google.silvercomet.client.Main$Resources

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.