fix(overlay): animation can be interrupted

fixes #15506
This commit is contained in:
Manu Mtz.-Almeida
2018-09-14 01:41:28 +02:00
parent 6e5c035b39
commit ca5866493b
3 changed files with 68 additions and 32 deletions

View File

@ -1152,6 +1152,9 @@ export class Animator {
* NO RECURSION * NO RECURSION
*/ */
_didFinish(hasCompleted: boolean) { _didFinish(hasCompleted: boolean) {
if (!this.isPlaying) {
return;
}
this.isPlaying = false; this.isPlaying = false;
this.hasCompleted = hasCompleted; this.hasCompleted = hasCompleted;
@ -1189,6 +1192,7 @@ export class Animator {
* Recursively destroy this animation and all child animations. * Recursively destroy this animation and all child animations.
*/ */
destroy() { destroy() {
this._didFinish(false);
this._destroyed = true; this._destroyed = true;
const children = this._childAnimations; const children = this._childAnimations;

View File

@ -22,6 +22,12 @@
<p> <p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentModal()">Present modal</ion-button> <ion-button id="presentModal" class="e2ePresentModal" onclick="presentModal()">Present modal</ion-button>
</p> </p>
<p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentCloseModal()">Present and close modal</ion-button>
</p>
<p>
<ion-button id="presentModal" class="e2ePresentModal" onclick="presentCloseModal2()">Present and close modal (crash)</ion-button>
</p>
</ion-content> </ion-content>
<ion-modal-controller></ion-modal-controller> <ion-modal-controller></ion-modal-controller>
@ -30,8 +36,8 @@
<script> <script>
window.addEventListener("ionModalDidDismiss", function (e) { console.log('DidDismiss', e) }) window.addEventListener("ionModalDidDismiss", function (e) { console.log('DidDismiss', e) })
window.addEventListener("ionModalWillDismiss", function (e) { console.log('WillDismiss', e) }) window.addEventListener("ionModalWillDismiss", function (e) { console.log('WillDismiss', e) })
async function presentModal() {
async function createModal() {
// initialize controller // initialize controller
const modalController = document.querySelector('ion-modal-controller'); const modalController = document.querySelector('ion-modal-controller');
await modalController.componentOnReady(); await modalController.componentOnReady();
@ -61,7 +67,25 @@
const modalElement = await modalController.create({ const modalElement = await modalController.create({
component: element component: element
}); });
modalElement.present(); return modalElement;
}
async function presentModal() {
const modal = await createModal();
await modal.present();
}
async function presentCloseModal() {
const modal = await createModal();
await modal.present();
await modal.dismiss();
}
async function presentCloseModal2() {
const modal = await createModal();
modal.present();
setTimeout(() => {
modal.dismiss();
}, 20);
} }
</script> </script>
</body> </body>

View File

@ -96,10 +96,11 @@ export async function present(
? overlay.enterAnimation ? overlay.enterAnimation
: overlay.config.get(name, overlay.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation); : overlay.config.get(name, overlay.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
await overlayAnimation(overlay, animationBuilder, overlay.el, opts); const completed = await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
if (completed) {
overlay.didPresent.emit(); overlay.didPresent.emit();
} }
}
export async function dismiss( export async function dismiss(
overlay: OverlayInterface, overlay: OverlayInterface,
@ -115,6 +116,7 @@ export async function dismiss(
} }
overlay.presented = false; overlay.presented = false;
try {
overlay.willDismiss.emit({ data, role }); overlay.willDismiss.emit({ data, role });
const animationBuilder = (overlay.leaveAnimation) const animationBuilder = (overlay.leaveAnimation)
@ -122,8 +124,12 @@ export async function dismiss(
: overlay.config.get(name, overlay.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation); : overlay.config.get(name, overlay.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
await overlayAnimation(overlay, animationBuilder, overlay.el, opts); await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
overlay.didDismiss.emit({ data, role }); overlay.didDismiss.emit({ data, role });
} catch (err) {
console.error(err);
}
overlay.el.remove(); overlay.el.remove();
return true; return true;
} }
@ -137,12 +143,13 @@ async function overlayAnimation(
animationBuilder: AnimationBuilder, animationBuilder: AnimationBuilder,
baseEl: HTMLElement, baseEl: HTMLElement,
opts: any opts: any
): Promise<void> { ): Promise<boolean> {
if (overlay.animation) { if (overlay.animation) {
overlay.animation.destroy(); overlay.animation.destroy();
overlay.animation = undefined; overlay.animation = undefined;
} return false;
} else {
// Make overlay visible in case it's hidden // Make overlay visible in case it's hidden
baseEl.classList.remove('ion-page-invisible'); baseEl.classList.remove('ion-page-invisible');
@ -161,9 +168,10 @@ async function overlayAnimation(
}); });
} }
await animation.playAsync(); await animation.playAsync();
animation.destroy(); animation.destroy();
overlay.animation = undefined; overlay.animation = undefined;
return animation.hasCompleted;
}
} }
export function autoFocus(containerEl: HTMLElement): HTMLElement | undefined { export function autoFocus(containerEl: HTMLElement): HTMLElement | undefined {