Java tutorial
/** * 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.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NodeList; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; import com.google.livingstories.client.lsp.views.Resources; import com.google.livingstories.client.util.LivingStoryControls; import com.google.livingstories.client.util.ObjectElementScrubber; /** * A PopupPanel that hides itself whenever the user clicks outside of it (optionally) * or on a link inside of it. */ public class AutoHidePopupPanel extends PopupPanel { public static String NON_HIDING_CLASS = "nonhiding"; private boolean wholePopupIsLink; private ObjectElementScrubber scrubber = GWT.create(ObjectElementScrubber.class); private boolean scrubbed; private boolean skipHide = false; public AutoHidePopupPanel() { this(true); } public AutoHidePopupPanel(boolean autoHide) { super(autoHide); } @Override public void setWidget(Widget w) { super.setWidget(w); scrubbed = false; } // the superclass add() method calls into setWidget, and thus needn't be overridden separately. @Override public void show() { if (scrubbed) { if (GWT.isScript()) { // just hide the dialog. The user's encountered a bug, but we don't want to put them // in a position where we need to instruct them what to do next. LivingStoryControls.showGlass(false); super.hide(); } else { // show a better error to developers: setAutoHideEnabled(true); super.setWidget(new Label("Error: the widget within this element was cleaned and cannot" + " safely be reshown without having its content reset first")); } } else { super.show(); } } @Override public void hide(boolean autoClosed) { if (skipHide) { skipHide = false; return; } if (getWidget() != null) { // clear the "data" attribute of all HTML objects within the widget, so that no playback // persists. NodeList<Element> objects = getWidget().getElement().getElementsByTagName("object"); for (int i = 0, len = objects.getLength(); i < len; i++) { scrubber.scrub(objects.getItem(i)); scrubbed = true; // in point of fact, we're safe in FF, but this indicates an implementation problem where // a popup is reused that shouldn't be, and we want to catch this on _all_ browsers. } } super.hide(autoClosed); } public void setWholePopupIsLink(boolean wholePopupIsLink) { this.wholePopupIsLink = wholePopupIsLink; } @Override protected void onPreviewNativeEvent(NativePreviewEvent event) { super.onPreviewNativeEvent(event); Event nativeEvent = Event.as(event.getNativeEvent()); if (nativeEvent.getTypeInt() == Event.ONMOUSEDOWN) { // This is a hack to make the popup panel not hide when the user drags // the window scrollbar thumb. // Since we are unable to override relevant methods to achieve this effect, // we just tell the hide() method to skip the next call it sees. if (nativeEvent.getClientX() > Window.getClientWidth() || nativeEvent.getClientY() > Window.getClientHeight()) { skipHide = true; } } else if (nativeEvent.getTypeInt() == Event.ONCLICK) { Element source = Element.as(nativeEvent.getEventTarget()); if (source.getClassName().contains(NON_HIDING_CLASS)) { return; } if (wholePopupIsLink || source.getTagName().equalsIgnoreCase("A") || source.getClassName().contains("primaryLink") || source.getClassName().contains("secondaryLink") || source.getClassName().contains(Resources.INSTANCE.css().clickable())) { // Need to use a deferred command here because if we hide the panel immediately, // it somehow prevents the link from seeing the event. DeferredCommand.addCommand(new Command() { @Override public void execute() { hide(); } }); } } else if (nativeEvent.getTypeInt() == Event.ONKEYUP && nativeEvent.getKeyCode() == KeyCodes.KEY_ESCAPE) { // also hide the dialog if that happens. Handy to provide this, in case the close // button somehow gets hidden offscreen. hide(); } } }