package com.eas.widgets.boxes; import java.util.ArrayList; import java.util.List; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; 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.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Event.NativePreviewHandler; import com.google.gwt.user.client.History; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; public class AutoCloseBox extends SimplePanel implements HasOpenHandlers<AutoCloseBox>, HasCloseHandlers<AutoCloseBox> { protected HandlerRegistration nativePreviewHandlerRegistration; protected HandlerRegistration historyHandlerRegistration; private List<Element> autoHidePartners; public AutoCloseBox() { super(); } public AutoCloseBox(Widget aContent) { this(); setWidget(aContent); } /** * Mouse events that occur within an autoHide partner will not hide a panel * set to autoHide. * * @param partner * the auto hide partner to add */ public void addAutoHidePartner(Element partner) { assert partner != null : "partner cannot be null"; if (autoHidePartners == null) { autoHidePartners = new ArrayList<Element>(); } autoHidePartners.add(partner); } /** * Remove an autoHide partner. * * @param partner * the auto hide partner to remove */ public void removeAutoHidePartner(Element partner) { assert partner != null : "partner cannot be null"; if (autoHidePartners != null) { autoHidePartners.remove(partner); } } public void show(Element aParentElement) { nativePreviewHandlerRegistration = Event.addNativePreviewHandler(new NativePreviewHandler() { public void onPreviewNativeEvent(NativePreviewEvent event) { previewNativeEvent(event); } }); historyHandlerRegistration = History.addValueChangeHandler(new ValueChangeHandler<String>() { public void onValueChange(ValueChangeEvent<String> event) { close(); } }); // Logical attach RootPanel.get().add(this); // Phisycal re-attach getElement().removeFromParent(); aParentElement.insertAfter(getElement(), aParentElement.getFirstChild()); if (getWidget() instanceof RequiresResize) { ((RequiresResize) getWidget()).onResize(); } OpenEvent.fire(this, this); } public void close() { if (nativePreviewHandlerRegistration != null) { nativePreviewHandlerRegistration.removeHandler(); nativePreviewHandlerRegistration = null; } if (historyHandlerRegistration != null) { historyHandlerRegistration.removeHandler(); historyHandlerRegistration = null; } removeFromParent(); CloseEvent.fire(this, this); } @Override public void setWidget(Widget w) { if (w != null) { w.getElement().getStyle().setWidth(100, Style.Unit.PCT); w.getElement().getStyle().setHeight(100, Style.Unit.PCT); w.getElement().getStyle().setDisplay(Style.Display.INLINE_BLOCK); } super.setWidget(w); } /** * Does the event target this popup? * * @param event * the native event * @return true if the event targets the popup */ private boolean eventTargetsPopup(NativeEvent event) { EventTarget target = event.getEventTarget(); if (Element.is(target)) { return getElement().isOrHasChild(Element.as(target)); } return false; } /** * Does the event target one of the partner elements? * * @param event * the native event * @return true if the event targets a partner */ private boolean eventTargetsPartner(NativeEvent event) { if (autoHidePartners == null) { return false; } EventTarget target = event.getEventTarget(); if (Element.is(target)) { for (Element elem : autoHidePartners) { if (elem.isOrHasChild(Element.as(target))) { return true; } } } return false; } /** * Preview the {@link NativePreviewEvent}. * * @param event * the {@link NativePreviewEvent} */ private void previewNativeEvent(NativePreviewEvent event) { // If the event has been canceled or consumed, ignore it if (!event.isCanceled()) { // If the event targets the auto close or the partner, consume it. Event nativeEvent = Event.as(event.getNativeEvent()); boolean eventTargetsPopupOrPartner = eventTargetsPopup(nativeEvent) || eventTargetsPartner(nativeEvent); if (eventTargetsPopupOrPartner) { event.consume(); } // Switch on the event type int type = nativeEvent.getTypeInt(); switch (type) { case Event.ONMOUSEDOWN: case Event.ONTOUCHSTART: // Don't eat events if event capture is enabled, as this can // interfere with dialog dragging, for example. if (DOM.getCaptureElement() != null) { event.consume(); return; } if (!eventTargetsPopupOrPartner) { close(); return; } break; case Event.ONMOUSEUP: case Event.ONMOUSEMOVE: case Event.ONCLICK: case Event.ONDBLCLICK: case Event.ONTOUCHEND: { // Don't eat events if event capture is enabled, as this can // interfere with dialog dragging, for example. if (DOM.getCaptureElement() != null) { event.consume(); return; } break; } case Event.ONFOCUS: { EventTarget evTarget = nativeEvent.getEventTarget(); if (Element.is(evTarget)) { Element target = Element.as(evTarget); if (!eventTargetsPopupOrPartner && (target != null)) { blur(target); event.cancel(); return; } } break; } } } } /** * Remove focus from an Element. * * @param elt * The Element on which <code>blur()</code> will be invoked */ private native void blur(Element elt) /*-{ // Issue 2390: blurring the body causes IE to disappear to the background if (elt.blur && elt != $doc.body) { elt.blur(); } }-*/; @Override public HandlerRegistration addCloseHandler(CloseHandler<AutoCloseBox> handler) { return addHandler(handler, CloseEvent.getType()); } @Override public HandlerRegistration addOpenHandler(OpenHandler<AutoCloseBox> handler) { return addHandler(handler, OpenEvent.getType()); } }