com.google.livingstories.client.ui.AutoHidePopupPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.google.livingstories.client.ui.AutoHidePopupPanel.java

Source

/**
 * 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();
        }
    }
}