Any running animation-in is now finished before animation-out is triggered. Moved windowClone variable into WindowConnector where it should be. Change-Id: I0ee733d05558d46a08e5e46f821104ad98783118tags/7.3.0.beta1
@@ -15,6 +15,7 @@ | |||
*/ | |||
package com.vaadin.client; | |||
import com.google.gwt.core.client.JavaScriptObject; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.NativeEvent; | |||
import com.google.gwt.dom.client.Style; | |||
@@ -57,7 +58,7 @@ public class AnimationUtil { | |||
} | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public static native void registerAnimationEndEventListener(Element elem, | |||
public static native JavaScriptObject addAnimationEndListener(Element elem, | |||
AnimationEndListener listener) | |||
/*-{ | |||
var callbackFunc = $entry(function(e) { | |||
@@ -71,10 +72,19 @@ public class AnimationUtil { | |||
elem._vaadin_animationend_callbacks = []; | |||
} | |||
elem._vaadin_animationend_callbacks.push(callbackFunc); | |||
return callbackFunc; | |||
}-*/; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public static native void removeAnimationEndListener(Element elem, | |||
JavaScriptObject listener) | |||
/*-{ | |||
elem.removeEventListener(@com.vaadin.client.AnimationUtil::ANIMATION_END_EVENT_NAME, listener, false); | |||
}-*/; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public static native void unregisterAnimationEndEventListeners(Element elem) | |||
public static native void removeAllAnimationEndListeners(Element elem) | |||
/*-{ | |||
if(elem._vaadin_animationend_callbacks) { | |||
var callbacks = elem._vaadin_animationend_callbacks; |
@@ -77,7 +77,7 @@ public class VNotification extends VOverlay { | |||
private static final ArrayList<VNotification> notifications = new ArrayList<VNotification>(); | |||
private boolean infiniteDelay = false; | |||
private int cssTransitionDelay = -1; | |||
private int cssAnimationDelay = -1; | |||
private int x = -1; | |||
private int y = -1; | |||
@@ -137,10 +137,10 @@ public class VNotification extends VOverlay { | |||
private void setDelay(int delayMsec) { | |||
if (delayMsec < 0) { | |||
infiniteDelay = true; | |||
cssTransitionDelay = 0; | |||
cssAnimationDelay = 0; | |||
} else { | |||
infiniteDelay = false; | |||
cssTransitionDelay = delayMsec; | |||
cssAnimationDelay = delayMsec; | |||
} | |||
} | |||
@@ -238,15 +238,16 @@ public class VNotification extends VOverlay { | |||
removeStyleDependentName(temporaryStyle); | |||
temporaryStyle = null; | |||
} | |||
if (style != null) { | |||
if (style != null && style.length() > 0) { | |||
temporaryStyle = style; | |||
addStyleName(style); | |||
addStyleDependentName(style); | |||
} | |||
setPosition(position); | |||
super.show(); | |||
updatePositionOffsets(position); | |||
notifications.add(this); | |||
setPosition(position); | |||
positionOrSizeUpdated(); | |||
/** | |||
* Android 4 fails to render notifications correctly without a little | |||
@@ -257,25 +258,53 @@ public class VNotification extends VOverlay { | |||
} | |||
} | |||
private void hideWithoutDelay() { | |||
cssAnimationDelay = 0; | |||
hide(); | |||
} | |||
@Override | |||
public void hide() { | |||
DOM.removeEventPreview(this); | |||
if (cssTransitionDelay >= 0) { | |||
AnimationUtil.setAnimationDelay(getElement(), cssTransitionDelay | |||
+ "ms"); | |||
// Run only once | |||
if (notifications.contains(this)) { | |||
DOM.removeEventPreview(this); | |||
if (cssAnimationDelay >= 0) { | |||
AnimationUtil.setAnimationDelay(getElement(), cssAnimationDelay | |||
+ "ms"); | |||
} | |||
super.hide(); | |||
notifications.remove(this); | |||
fireEvent(new HideEvent(this)); | |||
} | |||
super.hide(); | |||
notifications.remove(this); | |||
fireEvent(new HideEvent(this)); | |||
} | |||
public void setPosition(com.vaadin.shared.Position position) { | |||
private void updatePositionOffsets(com.vaadin.shared.Position position) { | |||
final Element el = getElement(); | |||
// Remove all offsets (GWT PopupPanel defaults) | |||
el.getStyle().clearTop(); | |||
el.getStyle().clearLeft(); | |||
switch (position) { | |||
case MIDDLE_LEFT: | |||
case MIDDLE_RIGHT: | |||
center(); | |||
el.getStyle().clearLeft(); | |||
break; | |||
case TOP_CENTER: | |||
case BOTTOM_CENTER: | |||
center(); | |||
el.getStyle().clearTop(); | |||
break; | |||
case MIDDLE_CENTER: | |||
center(); | |||
break; | |||
} | |||
} | |||
public void setPosition(com.vaadin.shared.Position position) { | |||
final Element el = getElement(); | |||
// Remove any previous positions | |||
el.removeClassName(STYLENAME_POSITION_TOP); | |||
el.removeClassName(STYLENAME_POSITION_RIGHT); | |||
@@ -295,16 +324,10 @@ public class VNotification extends VOverlay { | |||
el.addClassName(STYLENAME_POSITION_RIGHT); | |||
break; | |||
case MIDDLE_LEFT: | |||
center(); | |||
// Centering sets the left offset | |||
el.getStyle().clearLeft(); | |||
el.addClassName(STYLENAME_POSITION_MIDDLE); | |||
el.addClassName(STYLENAME_POSITION_LEFT); | |||
break; | |||
case MIDDLE_RIGHT: | |||
center(); | |||
// Centering sets the left offset | |||
el.getStyle().clearLeft(); | |||
el.addClassName(STYLENAME_POSITION_MIDDLE); | |||
el.addClassName(STYLENAME_POSITION_RIGHT); | |||
break; | |||
@@ -317,32 +340,21 @@ public class VNotification extends VOverlay { | |||
el.addClassName(STYLENAME_POSITION_LEFT); | |||
break; | |||
case TOP_CENTER: | |||
center(); | |||
// Centering sets the top offset | |||
el.getStyle().clearTop(); | |||
el.addClassName(STYLENAME_POSITION_TOP); | |||
el.addClassName(STYLENAME_POSITION_CENTER); | |||
break; | |||
case BOTTOM_CENTER: | |||
center(); | |||
// Centering sets the top offset | |||
el.getStyle().clearTop(); | |||
el.addClassName(STYLENAME_POSITION_BOTTOM); | |||
el.addClassName(STYLENAME_POSITION_CENTER); | |||
break; | |||
case ASSISTIVE: | |||
el.addClassName(STYLENAME_POSITION_ASSISTIVE); | |||
break; | |||
default: | |||
case MIDDLE_CENTER: | |||
center(); | |||
break; | |||
} | |||
} | |||
@Override | |||
public void onBrowserEvent(Event event) { | |||
DOM.removeEventPreview(this); | |||
hide(); | |||
} | |||
@@ -353,12 +365,12 @@ public class VNotification extends VOverlay { | |||
if (infiniteDelay || temporaryStyle == STYLE_SYSTEM) { | |||
if (type == Event.ONCLICK) { | |||
if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) { | |||
hide(); | |||
hideWithoutDelay(); | |||
return false; | |||
} | |||
} else if (type == Event.ONKEYDOWN | |||
&& event.getKeyCode() == KeyCodes.KEY_ESCAPE) { | |||
hide(); | |||
hideWithoutDelay(); | |||
return false; | |||
} | |||
if (temporaryStyle == STYLE_SYSTEM) { | |||
@@ -370,7 +382,6 @@ public class VNotification extends VOverlay { | |||
// default | |||
switch (type) { | |||
case Event.ONMOUSEMOVE: | |||
if (x < 0) { | |||
x = DOM.eventGetClientX(event); | |||
y = DOM.eventGetClientY(event); |
@@ -21,13 +21,13 @@ import java.util.logging.Logger; | |||
import com.google.gwt.animation.client.Animation; | |||
import com.google.gwt.aria.client.Roles; | |||
import com.google.gwt.core.client.JavaScriptObject; | |||
import com.google.gwt.dom.client.Document; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.IFrameElement; | |||
import com.google.gwt.dom.client.NativeEvent; | |||
import com.google.gwt.dom.client.Style; | |||
import com.google.gwt.dom.client.Style.BorderStyle; | |||
import com.google.gwt.dom.client.Style.Display; | |||
import com.google.gwt.dom.client.Style.Position; | |||
import com.google.gwt.dom.client.Style.Unit; | |||
import com.google.gwt.event.logical.shared.CloseEvent; | |||
@@ -443,6 +443,8 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { | |||
current = null; | |||
} | |||
private JavaScriptObject animateInListener; | |||
private boolean maybeShowWithAnimation() { | |||
boolean isAttached = isAttached() && isShowing(); | |||
super.show(); | |||
@@ -467,8 +469,25 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { | |||
} | |||
if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) { | |||
AnimationUtil.registerAnimationEndEventListener(getElement(), | |||
getAnimationEndListener(false)); | |||
animateInListener = AnimationUtil.addAnimationEndListener( | |||
getElement(), new AnimationEndListener() { | |||
@Override | |||
public void onAnimationEnd(NativeEvent event) { | |||
String animationName = AnimationUtil | |||
.getAnimationName(event); | |||
if (animationName | |||
.contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) { | |||
AnimationUtil.removeAnimationEndListener( | |||
getElement(), animateInListener); | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
if (isShadowEnabled()) { | |||
shadow.removeClassName(CLASSNAME_SHADOW | |||
+ "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
} | |||
} | |||
} | |||
}); | |||
return true; | |||
} else { | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
@@ -936,64 +955,75 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { | |||
* @see com.google.gwt.user.client.ui.PopupPanel#hide(boolean) | |||
*/ | |||
@Override | |||
public void hide(boolean autoClosed) { | |||
public void hide(final boolean autoClosed) { | |||
if (BrowserInfo.get().isIE8() || BrowserInfo.get().isIE9()) { | |||
super.hide(autoClosed); | |||
} else { | |||
// Check if animations are used | |||
addStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
if (isShadowEnabled()) { | |||
shadow.addClassName(CLASSNAME_SHADOW + "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
} | |||
ComputedStyle cs = new ComputedStyle(getElement()); | |||
String animationName = AnimationUtil.getAnimationName(cs); | |||
if (animationName == null) { | |||
animationName = ""; | |||
} | |||
if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) { | |||
AnimationUtil.registerAnimationEndEventListener(getElement(), | |||
getAnimationEndListener(autoClosed)); | |||
// No event previews should happen after the animation has | |||
// started | |||
VOverlay.this.setPreviewingAllNativeEvents(false); | |||
if (getStyleName().contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) { | |||
AnimationUtil.addAnimationEndListener(getElement(), | |||
new AnimationEndListener() { | |||
@Override | |||
public void onAnimationEnd(NativeEvent event) { | |||
if (AnimationUtil | |||
.getAnimationName(event) | |||
.contains( | |||
ADDITIONAL_CLASSNAME_ANIMATE_IN)) { | |||
VOverlay.this.hide(autoClosed); | |||
} | |||
} | |||
}); | |||
} else { | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
// Check if animations are used | |||
addStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
if (isShadowEnabled()) { | |||
shadow.removeClassName(CLASSNAME_SHADOW + "-" | |||
shadow.addClassName(CLASSNAME_SHADOW + "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
} | |||
super.hide(autoClosed); | |||
} | |||
} | |||
} | |||
private AnimationEndListener getAnimationEndListener( | |||
final boolean autoClosed) { | |||
return new AnimationEndListener() { | |||
ComputedStyle cs = new ComputedStyle(getElement()); | |||
String animationName = AnimationUtil.getAnimationName(cs); | |||
if (animationName == null) { | |||
animationName = ""; | |||
} | |||
@Override | |||
public void onAnimationEnd(NativeEvent event) { | |||
AnimationUtil | |||
.unregisterAnimationEndEventListeners(getElement()); | |||
String animationName = AnimationUtil.getAnimationName(event); | |||
if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) { | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
if (isShadowEnabled()) { | |||
shadow.removeClassName(CLASSNAME_SHADOW + "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
} | |||
} else if (animationName | |||
.contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) { | |||
if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) { | |||
AnimationUtil.addAnimationEndListener(getElement(), | |||
new AnimationEndListener() { | |||
@Override | |||
public void onAnimationEnd(NativeEvent event) { | |||
String animationName = AnimationUtil | |||
.getAnimationName(event); | |||
if (animationName | |||
.contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) { | |||
AnimationUtil | |||
.removeAllAnimationEndListeners(getElement()); | |||
// Remove both animation styles just in | |||
// case | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
if (isShadowEnabled()) { | |||
shadow.removeClassName(CLASSNAME_SHADOW | |||
+ "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_IN); | |||
shadow.removeClassName(CLASSNAME_SHADOW | |||
+ "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
} | |||
VOverlay.super.hide(autoClosed); | |||
} | |||
} | |||
}); | |||
// No event previews should happen after the animation has | |||
// started | |||
VOverlay.this.setPreviewingAllNativeEvents(false); | |||
} else { | |||
removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
if (isShadowEnabled()) { | |||
shadow.removeClassName(CLASSNAME_SHADOW + "-" | |||
+ ADDITIONAL_CLASSNAME_ANIMATE_OUT); | |||
} | |||
VOverlay.super.hide(autoClosed); | |||
super.hide(autoClosed); | |||
} | |||
} | |||
}; | |||
} | |||
} | |||
} |
@@ -30,7 +30,6 @@ import com.google.gwt.core.client.Scheduler.ScheduledCommand; | |||
import com.google.gwt.dom.client.Document; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.NativeEvent; | |||
import com.google.gwt.dom.client.Node; | |||
import com.google.gwt.dom.client.Style; | |||
import com.google.gwt.dom.client.Style.Display; | |||
import com.google.gwt.dom.client.Style.Position; | |||
@@ -201,9 +200,6 @@ public class VWindow extends VWindowOverlay implements | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public int bringToFrontSequence = -1; | |||
/** For internal use only. May be removed or replaced in the future. */ | |||
public Node windowClone; | |||
private VLazyExecutor delayedContentsSizeUpdater = new VLazyExecutor(200, | |||
new ScheduledCommand() { | |||
@@ -1037,14 +1033,6 @@ public class VWindow extends VWindowOverlay implements | |||
} | |||
private void onCloseClick() { | |||
// Take a copy of the contents, since the server will detach all | |||
// children of this window, and the window will be emptied during the | |||
// next hierarchy update (we need to keep the contents visible for the | |||
// duration of a possible 'out-animation') | |||
// This is used by the WindowConnector in the case the window is | |||
// actually closed and removed from the UI | |||
windowClone = getElement().getFirstChild().cloneNode(true); | |||
// Send the close event to the server | |||
client.updateVariable(id, "close", true, true); | |||
} |
@@ -19,6 +19,7 @@ import java.util.logging.Logger; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.dom.client.NativeEvent; | |||
import com.google.gwt.dom.client.Node; | |||
import com.google.gwt.dom.client.Style; | |||
import com.google.gwt.dom.client.Style.Position; | |||
import com.google.gwt.dom.client.Style.Unit; | |||
@@ -58,6 +59,8 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector | |||
SimpleManagedLayout, PostLayoutListener, MayScrollChildren, | |||
WindowMoveHandler { | |||
private Node windowClone; | |||
private ClickEventHandler clickEventHandler = new ClickEventHandler(this) { | |||
@Override | |||
protected void fireClick(NativeEvent event, | |||
@@ -193,14 +196,16 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector | |||
// We always have 1 child, unless the child is hidden | |||
getWidget().contentPanel.setWidget(getContentWidget()); | |||
// If the window is removed from the UI, add the copy of the contents to | |||
// the window (in case of an 'out-animation') | |||
if (getParent() == null) { | |||
if (getParent() == null && windowClone != null) { | |||
// If the window is removed from the UI, add the copy of the | |||
// contents to the window (in case of an 'out-animation') | |||
getWidget().getElement().removeAllChildren(); | |||
getWidget().getElement().appendChild(getWidget().windowClone); | |||
getWidget().getElement().appendChild(windowClone); | |||
// Clean reference | |||
windowClone = null; | |||
} | |||
// Clean reference | |||
getWidget().windowClone = null; | |||
} | |||
@Override | |||
@@ -277,6 +282,16 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector | |||
window.center(); | |||
} | |||
window.positionOrSizeUpdated(); | |||
if (getParent() != null) { | |||
// Take a copy of the contents, since the server will detach all | |||
// children of this window when it's closed, and the window will be | |||
// emptied during the following hierarchy update (we need to keep | |||
// the contents visible for the duration of a possible | |||
// 'out-animation') | |||
windowClone = getWidget().getElement().getFirstChild() | |||
.cloneNode(true); | |||
} | |||
} | |||
@Override |