From ca5866493b447a5a54e6cc78cdfd832a61a2e40f Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Fri, 14 Sep 2018 01:41:28 +0200 Subject: [PATCH] fix(overlay): animation can be interrupted fixes #15506 --- .../animation-controller/animator.tsx | 4 ++ .../components/modal/test/basic/index.html | 28 +++++++- core/src/utils/overlays.ts | 68 +++++++++++-------- 3 files changed, 68 insertions(+), 32 deletions(-) diff --git a/core/src/components/animation-controller/animator.tsx b/core/src/components/animation-controller/animator.tsx index 5386397d87..0d1c0bf1af 100644 --- a/core/src/components/animation-controller/animator.tsx +++ b/core/src/components/animation-controller/animator.tsx @@ -1152,6 +1152,9 @@ export class Animator { * NO RECURSION */ _didFinish(hasCompleted: boolean) { + if (!this.isPlaying) { + return; + } this.isPlaying = false; this.hasCompleted = hasCompleted; @@ -1189,6 +1192,7 @@ export class Animator { * Recursively destroy this animation and all child animations. */ destroy() { + this._didFinish(false); this._destroyed = true; const children = this._childAnimations; diff --git a/core/src/components/modal/test/basic/index.html b/core/src/components/modal/test/basic/index.html index 801fef7866..7526493f2f 100644 --- a/core/src/components/modal/test/basic/index.html +++ b/core/src/components/modal/test/basic/index.html @@ -22,6 +22,12 @@

Present modal

+

+ Present and close modal +

+

+ Present and close modal (crash) +

@@ -30,8 +36,8 @@ diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 95daca3cbd..f46ff1402b 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -96,9 +96,10 @@ export async function present( ? overlay.enterAnimation : overlay.config.get(name, overlay.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation); - await overlayAnimation(overlay, animationBuilder, overlay.el, opts); - - overlay.didPresent.emit(); + const completed = await overlayAnimation(overlay, animationBuilder, overlay.el, opts); + if (completed) { + overlay.didPresent.emit(); + } } export async function dismiss( @@ -115,15 +116,20 @@ export async function dismiss( } overlay.presented = false; - overlay.willDismiss.emit({ data, role }); + try { + overlay.willDismiss.emit({ data, role }); - const animationBuilder = (overlay.leaveAnimation) - ? overlay.leaveAnimation - : overlay.config.get(name, overlay.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation); + const animationBuilder = (overlay.leaveAnimation) + ? overlay.leaveAnimation + : 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 }); + + } catch (err) { + console.error(err); + } - overlay.didDismiss.emit({ data, role }); overlay.el.remove(); return true; } @@ -137,33 +143,35 @@ async function overlayAnimation( animationBuilder: AnimationBuilder, baseEl: HTMLElement, opts: any -): Promise { +): Promise { if (overlay.animation) { overlay.animation.destroy(); overlay.animation = undefined; - } + return false; - // Make overlay visible in case it's hidden - baseEl.classList.remove('ion-page-invisible'); + } else { + // Make overlay visible in case it's hidden + baseEl.classList.remove('ion-page-invisible'); - const aniRoot = baseEl.shadowRoot || overlay.el; - const animation = overlay.animation = await overlay.animationCtrl.create(animationBuilder, aniRoot, opts); - overlay.animation = animation; - if (!overlay.animated) { - animation.duration(0); + const aniRoot = baseEl.shadowRoot || overlay.el; + const animation = overlay.animation = await overlay.animationCtrl.create(animationBuilder, aniRoot, opts); + overlay.animation = animation; + if (!overlay.animated) { + animation.duration(0); + } + if (overlay.keyboardClose) { + animation.beforeAddWrite(() => { + const activeElement = baseEl.ownerDocument.activeElement as HTMLElement; + if (activeElement && activeElement.matches('input, ion-input, ion-textarea')) { + activeElement.blur(); + } + }); + } + await animation.playAsync(); + animation.destroy(); + overlay.animation = undefined; + return animation.hasCompleted; } - if (overlay.keyboardClose) { - animation.beforeAddWrite(() => { - const activeElement = baseEl.ownerDocument.activeElement as HTMLElement; - if (activeElement && activeElement.matches('input, ion-input, ion-textarea')) { - activeElement.blur(); - } - }); - } - await animation.playAsync(); - - animation.destroy(); - overlay.animation = undefined; } export function autoFocus(containerEl: HTMLElement): HTMLElement | undefined {