Package com.google.livingstories.client.ui

Source Code of com.google.livingstories.client.ui.PartialDisclosurePanel$ClickableHeader

/**
* 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.ui;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
import com.google.gwt.event.logical.shared.HasOpenHandlers;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasAnimation;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.livingstories.client.util.Constants;
import com.google.livingstories.client.util.LivingStoryControls;

import java.util.List;

/**
* A widget that consists of a header and a content panel.  Some items within the
* content panel are initially hidden, and clicking the header will toggle the display
* state of these items.  The panel will also animate, expanding and collapsing
* to accomodate these elements.
*
* This class uses the same style rules as the standard gwt DisclosurePanel.
* .gwt-DisclosurePanel { the panel's primary style }
* .gwt-DisclosurePanel-open { dependent style set when panel is open }
* .gwt-DisclosurePanel-closed { dependent style set when panel is closed }
* .gwt-DisclosurePanel .header { style for the header }
* .gwt-DisclosurePanel .content { style for the content }
*
* Quite a bit of this code comes directly from the standard DisclosurePanel itself;
* however, extending that class didn't seem practical for our use case, so we rewrite
* some functionality here.
*/
public final class PartialDisclosurePanel extends Composite implements HasAnimation,
    HasOpenHandlers<PartialDisclosurePanel>, HasCloseHandlers<PartialDisclosurePanel>,
    HasClickHandlers {
  /**
   * Used to wrap widgets in the header to provide click support. Effectively
   * wraps the widget in an <code>anchor</code> to get automatic keyboard
   * access.
   */
  private final class ClickableHeader extends SimplePanel implements HasClickHandlers {

    private ClickableHeader() {
      // Anchor is used to allow keyboard access.
      super(DOM.createAnchor());
      Element elem = getElement();
      DOM.setElementProperty(elem, "href", "javascript:void(0);");
      // Avoids layout problems from having blocks in inlines.
      DOM.setStyleAttribute(elem, "display", "block");
      sinkEvents(Event.ONCLICK);
      setStyleName(STYLENAME_HEADER);
    }
   
    public HandlerRegistration addClickHandler(ClickHandler handler) {
      return addHandler(handler, ClickEvent.getType());
    }

    @Override
    public void onBrowserEvent(Event event) {
      // no need to call super.
      switch (DOM.eventGetType(event)) {
        case Event.ONCLICK:
          // Prevent link default action.
          DOM.eventPreventDefault(event);
          ClickEvent.fireNativeEvent(event, this);
          setOpen(!isOpen);
      }
    }
  }

  // Stylename constants.
  private static final String STYLENAME_DEFAULT = "gwt-DisclosurePanel";

  private static final String STYLENAME_SUFFIX_OPEN = "open";

  private static final String STYLENAME_SUFFIX_CLOSED = "closed";

  private static final String STYLENAME_HEADER = "header";

  private static final String STYLENAME_CONTENT = "content";

  private final VerticalPanel mainPanel = new VerticalPanel();
  private final ClickableHeader header = new ClickableHeader();
  private final SimplePanel contentWrapper = new SimplePanel();

  private boolean isAnimationEnabled = false;
  private boolean isOpen = false;
  private List<Widget> toggledWidgets;
  private Command onAnimationCompletion;
  private Command oneTimeOnAnimationCompletion;
 
  public PartialDisclosurePanel(boolean headerOnTop) {
    init(headerOnTop);
  }
 
  public PartialDisclosurePanel(Widget panelHeader, boolean headerOnTop) {
    this(headerOnTop);
    setHeader(panelHeader);
  }

  public HandlerRegistration addCloseHandler(
      CloseHandler<PartialDisclosurePanel> handler) {
    return addHandler(handler, CloseEvent.getType());
  }

  public HandlerRegistration addOpenHandler(
      OpenHandler<PartialDisclosurePanel> handler) {
    return addHandler(handler, OpenEvent.getType());
  }

  public HandlerRegistration addClickHandler(ClickHandler handler) {
    return header.addClickHandler(handler);
  }
 
  public void setAnimationCompletionCommand(Command onAnimationCompletion) {
    this.onAnimationCompletion = onAnimationCompletion;
  }
 
  public void clear() {
    setContent(null, null);
  }

  public Widget getContent() {
    return contentWrapper.getWidget();
  }

  public Widget getHeader() {
    return header.getWidget();
  }

  public HasText getHeaderTextAccessor() {
    Widget widget = header.getWidget();
    return (widget instanceof HasText) ? (HasText) widget : null;
  }
 
  public boolean isAnimationEnabled() {
    return isAnimationEnabled;
  }

  public boolean isOpen() {
    return isOpen;
  }

  public void setAnimationEnabled(boolean enable) {
    isAnimationEnabled = enable;
  }
 
  /**
   * Sets the content widget which can be opened and closed by this panel. If
   * there is a preexisting content widget, it will be detached.
   *
   * @param content the widget to be used as the content panel
   * @param toggledWidgets items that will be shown and hidden by this panel.
   */
  public void setContent(Widget content, List<Widget> toggledWidgets) {
    final Widget currentContent = getContent();

    // Remove existing content widget.
    if (currentContent != null) {
      contentWrapper.setWidget(null);
      this.toggledWidgets = null;
      currentContent.removeStyleName(STYLENAME_CONTENT);
    }

    // Add new content widget if != null.
    if (content != null) {
      contentWrapper.setWidget(content);
      this.toggledWidgets = toggledWidgets;
      content.addStyleName(STYLENAME_CONTENT);
    }
  }

  /**
   * Sets the widget used as the header for the panel.
   *
   * @param headerWidget the widget to be used as the header
   */
  public void setHeader(Widget headerWidget) {
    header.setWidget(headerWidget);
  }

  /**
   * Changes the visible state of this <code>DisclosurePanel</code>.
   *
   * @param isOpen <code>true</code> to open the panel, <code>false</code> to
   * close
   */
  public void setOpen(boolean isOpen) {
    if (this.isOpen != isOpen) {
      this.isOpen = isOpen;
      setContentDisplay(isAnimationEnabled);
      fireEvent();
    }
  }

  public void scrollToContainedWidget(final Widget w) {
    Command doScroll = new Command() {
      @Override
      public void execute() {
        Window.scrollTo(0, w.getElement().getAbsoluteTop());
        LivingStoryControls.repositionAnchoredPanel();
      }
    };

    if (isOpen()) {
      doScroll.execute();
    } else {
      setOneTimeAnimationCompletionCommand(doScroll);
      setOpen(true);
    }
  }

  /**
   * <b>Affected Elements:</b>
   * <ul>
   * <li>-header = the clickable header.</li>
   * </ul>
   *
   * @see UIObject#onEnsureDebugId(String)
   */
  @Override
  protected void onEnsureDebugId(String baseID) {
    super.onEnsureDebugId(baseID);
    header.ensureDebugId(baseID + "-header");
  }

  private void setOneTimeAnimationCompletionCommand(Command oneTimeOnAnimationCompletion) {
    this.oneTimeOnAnimationCompletion = oneTimeOnAnimationCompletion;
  }
         

  private void fireEvent() {
    if (isOpen) {
      OpenEvent.fire(this, this);
    } else {
      CloseEvent.fire(this, this);
    }
  }

  private void init(boolean headerOnTop) {
    initWidget(mainPanel);
    if (headerOnTop) {
      mainPanel.add(header);
      mainPanel.add(contentWrapper);
    } else {
      mainPanel.add(contentWrapper);
      mainPanel.add(header);
    }
    DOM.setStyleAttribute(contentWrapper.getElement(), "padding", "0px");
    DOM.setStyleAttribute(contentWrapper.getElement(), "overflow", "hidden");
    setStyleName(STYLENAME_DEFAULT);
    addStyleDependentName(STYLENAME_SUFFIX_CLOSED);
  }

  private void setContentDisplay(boolean animate) {
    if (isOpen) {
      removeStyleDependentName(STYLENAME_SUFFIX_CLOSED);
      addStyleDependentName(STYLENAME_SUFFIX_OPEN);
    } else {
      removeStyleDependentName(STYLENAME_SUFFIX_OPEN);
      addStyleDependentName(STYLENAME_SUFFIX_CLOSED);
    }

    if (getContent() != null) {
      int oldHeight = getContent().getElement().getClientHeight();
      DOM.setStyleAttribute(contentWrapper.getElement(), "height", oldHeight + "px");
     
      for (Widget widget : toggledWidgets) {
        widget.setVisible(!widget.isVisible());
      }

      int newHeight = getContent().getElement().getClientHeight();

      if (animate) {
        ExpandEffect animation = new ExpandEffect(contentWrapper, newHeight);
        animation.run(Constants.ANIMATION_DURATION);
      } else {
        DOM.setStyleAttribute(contentWrapper.getElement(), "height", "auto");
        runCompletionCode();
      }
    }
  }
 
  private class ExpandEffect extends StyleEffect {
    public ExpandEffect(Widget widget, int newValue) {
      super(widget, "height", newValue);
    }

    @Override
    public void onComplete() {
      DOM.setStyleAttribute(widget.getElement(), "height", "auto");
      runCompletionCode();
    }
  }
 
  private void runCompletionCode() {
    // for IE friendliness, we always run the completion code via the DeferredCommand
    // mechanism.
    DeferredCommand.addCommand(new Command() {
      @Override
      public void execute() {
        if (onAnimationCompletion != null) {
          onAnimationCompletion.execute();
        }
        if (oneTimeOnAnimationCompletion != null) {
          oneTimeOnAnimationCompletion.execute();
          oneTimeOnAnimationCompletion = null;
        }
      }
    });
  }
}
TOP

Related Classes of com.google.livingstories.client.ui.PartialDisclosurePanel$ClickableHeader

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.