package org.tessell.widgets; import static org.tessell.widgets.Widgets.getWindow; import static org.tessell.widgets.Widgets.newFadingDialogBox; import static org.tessell.widgets.Widgets.newScrollPanel; import org.tessell.gwt.user.client.IsWindow; import org.tessell.gwt.user.client.ui.IsScrollPanel; import org.tessell.gwt.user.client.ui.IsWidget; import org.tessell.presenter.BasicPresenter; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.PopupPanel; /** For showing views in a lightbox popup. */ public abstract class AbstractLightboxPresenter<V extends IsWidget> extends BasicPresenter<V> { protected final IsWindow window = getWindow(); protected final IsFadingDialogBox box = newFadingDialogBox(); protected final IsScrollPanel scroll = newScrollPanel(); public AbstractLightboxPresenter(final V view) { super(view); } protected void setWidth(final int pixels) { scroll.getStyle().setWidth(pixels, Unit.PX); } @Override public void onBind() { super.onBind(); box.setAnimationEnabled(true); box.setAutoFadeInElement(false); // we'll fade in the element when ready box.setGlassEnabled(true); box.setWidget(scroll); box.getStyle().setZIndex(2); scroll.setAlwaysShowScrollBars(false); // If the vertical scroll bar shows up, it will take some horizontal space // and cause our content to overflow by 5-whatever pixels. Ignore that. scroll.getStyle().setProperty("overflowX", Overflow.HIDDEN.getCssName()); scroll.getStyle().setBackgroundColor("#FFFFFF"); scroll.add(view); if (GWT.isClient()) { // fix weird bug where the margin:0 in the css reset made the vertical scroll bar always show up ((Element) scroll.getIsElement().asElement().getChild(0)).getStyle().setMargin(1, Unit.PX); } // selenium tests attempting to type into light boxes will hit the // dummy-click-div and cause the lightbox to close unless we add it // as an auto-hide partner. Hide this hack behind a GWT.isClient. if (GWT.isClient()) { final Element clickdiv = DOM.getElementById("dummy-click-div"); if (clickdiv != null) { ((PopupPanel) box).addAutoHidePartner(clickdiv); } } registerHandler(box.addCloseHandler(new OnBoxClose())); registerHandler(window.addResizeHandler(new OnResize())); } protected void center() { box.center(); final int offsetHeight = view.getOffsetHeight(); // 100 = how far we position ourselves from the top (see next step), 20 = 10 top gray bar + 10 bottom gray bar final int availHeight = window.getClientHeight() - 100 - 20; if (availHeight < offsetHeight) { scroll.getStyle().setHeight(Math.max(availHeight, 0), Unit.PX); } else { scroll.getStyle().clearHeight(); } scroll.onResize(); // We used to just center, but instead want horizontal center and top to be from top // copy/paste from box.center() with top hardcoded to 100 final int left = (window.getClientWidth() - view.getOffsetWidth()) >> 1; final int top = 100; // (window.getClientHeight() - box.getOffsetHeight()) >> 1; box.setPopupPosition(Math.max(window.getScrollLeft() + left, 0), Math.max(window.getScrollTop() + top, 0)); } protected void centerAndFadeIfFirst() { if (!box.isShowing()) { center(); fadeInElement(); } else { center(); } } protected void hide() { box.hide(); } protected void fadeInElement() { box.fadeInElement(); } protected void fadeOutElement() { box.fadeOutElement(); } /** Means the user cannot close the popup by clicking around. */ protected void setSuperModal() { box.setAutoHideEnabled(false); } /** Make sure we stay centered. */ private class OnResize implements ResizeHandler { public void onResize(final ResizeEvent event) { if (box.isShowing()) { center(); } } } /** Unbinds ourself when the box closes. */ private class OnBoxClose implements CloseHandler<PopupPanel> { public void onClose(final CloseEvent<PopupPanel> event) { unbind(); } } // for testing public IsFadingDialogBox getBox() { return box; } }