/**
* 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 org.waveprotocol.wave.client.autohide;
import com.google.gwt.dom.client.Element;
import java.util.ArrayList;
import java.util.List;
/**
* AutoHiders are registered by entities that want to be automatically hidden
* when the user performs a particular global UI action, such as clicking
* outside the containing element of the entity in question.
*
* An AutoHider is registered if it is being applied to incoming events. It is
* possible to have an AutoHider that exists, but is not being used to respond
* to incoming events.
*
*/
public class AutoHider implements Hideable {
/** How sensitive a Hideable is autohide triggers. */
public enum KeyBehavior {
DO_NOT_HIDE_ON_ANY_KEY,
HIDE_ON_ESCAPE,
/** "Hide on any key" also includes mouse-wheel events as "key event". */
HIDE_ON_ANY_KEY
}
/**
* The thing that gets hidden when an appropriate event is detected.
*/
private final Hideable hideable;
/**
* Whether or not to hide when a click event occurs outside a given element.
*/
private final boolean hideOnOutsideClick;
/**
* Whether or not to hide when any key (or just the escape key) is pressed.
*/
private final KeyBehavior keyBehavior;
/**
* Whether or not to hide when the window is resized.
*/
private final boolean hideOnWindowResize;
/**
* Whether or not to hide when moving in browser history (e.g., back button).
*/
private final boolean hideOnHistoryEvent;
/**
* Whether or not this AutoHider has been registered and is listening to
* events at the event preview level.
*/
private boolean isRegistered = false;
/**
* Used to determine whether which parent elements are considered 'inside' the thing being hidden,
* and so clicks must not be contained in these to be considered 'outside' and enough to hide it.
*/
private final List<Element> insideElements = new ArrayList<Element>();
/**
* @param hideable Gets hidden on appropriate event.
* @param hideOnOutsideClick Should a click outside the entity cause an auto-hide?
* @param hideOnWindowResize Should resizing the window cause an auto-hide?
* @param hideOnHistoryEvent Should moving back or forward in browser history cause an auto-hide?
* @param keyBehavior Should pressing a key cause an auto-hide?
*/
public AutoHider(Hideable hideable,
boolean hideOnOutsideClick,
boolean hideOnWindowResize,
boolean hideOnHistoryEvent,
KeyBehavior keyBehavior) {
this.hideable = hideable;
this.hideOnOutsideClick = hideOnOutsideClick;
this.hideOnWindowResize = hideOnWindowResize;
this.hideOnHistoryEvent = hideOnHistoryEvent;
this.keyBehavior = keyBehavior;
}
/**
* @return Whether or not we should hide when any key is pressed.
*/
public boolean shouldHideOnAnyKey() {
return keyBehavior == KeyBehavior.HIDE_ON_ANY_KEY;
}
/**
* @return Whether or not we should hide when the escape key is pressed.
*/
public boolean shouldHideOnEscape() {
return keyBehavior == KeyBehavior.HIDE_ON_ESCAPE || keyBehavior == KeyBehavior.HIDE_ON_ANY_KEY;
}
/**
* @return Whether or not we should hide when a click occurs outside of the
* entity.
*/
public boolean shouldHideOnOutsideClick() {
return hideOnOutsideClick;
}
/**
* @return Whether or not we should hide when the window is resized.
*/
public boolean shouldHideOnWindowResize() {
return hideOnWindowResize;
}
/**
* @return Whether or not we should hide when moving in browser history
*/
public boolean shouldHideOnHistoryEvent() {
return hideOnHistoryEvent;
}
/**
* @return Whether or not this AutoHider is registered.
*/
public boolean isRegistered() {
return isRegistered;
}
/**
* Whitelists an element so that clicking on it does not hide the item this hider is for.
*
* @param element The element to use to determine whether click events are
* inside or outside.
*/
public void ignoreHideClickFor(Element element) {
this.insideElements.add(element);
}
/**
* @param isRegistered Whether or not this AutoHider is registered.
*/
public void setRegistered(boolean isRegistered) {
this.isRegistered = isRegistered;
}
@Override
public void hide() {
hideable.hide();
}
@Override
public boolean isShowing() {
return hideable.isShowing();
}
/**
* @param target An element.
* @return {@code true} if the given element is considered to be inside the
* entity.
*/
public boolean doesContain(Element target) {
for (Element element : insideElements) {
if (element.isOrHasChild(target)) {
return true;
}
}
return false;
}
}