diff --git a/core/src/utils/animation/animation.ts b/core/src/utils/animation/animation.ts index f71e41f142..ed4cd7759a 100644 --- a/core/src/utils/animation/animation.ts +++ b/core/src/utils/animation/animation.ts @@ -140,12 +140,39 @@ export class Animation { childAnimation.destroy(); }); + this.cleanUp(); + this.elements = []; this.childAnimations = []; + this.initialized = false; + return this; } + private cleanUp(): void { + this.cleanUpElements(); + this.cleanUpStyleSheets(); + } + + private cleanUpElements(): void { + this.elements.forEach(element => { + element.style.removeProperty('animation-name'); + element.style.removeProperty('animation-duration'); + element.style.removeProperty('animation-timing-function'); + element.style.removeProperty('animation-iteration-count'); + element.style.removeProperty('animation-delay'); + element.style.removeProperty('animation-play-state'); + }); + } + + private cleanUpStyleSheets() { + if (this.stylesheet) { + this.stylesheet.parentNode!.removeChild(this.stylesheet); + this.stylesheet = undefined; + } + } + /** * Add CSS class to this animation's elements * before the animation begins. @@ -364,25 +391,7 @@ export class Animation { } }); - this.cleanUpDOM(); - } - - private cleanUpDOM() { - if (this.stylesheet) { - this.stylesheet.parentNode!.removeChild(this.stylesheet); - this.stylesheet = undefined; - } - - this.elements.forEach(element => { - element.style.removeProperty('animation-name'); - element.style.removeProperty('animation-duration'); - element.style.removeProperty('animation-timing-function'); - element.style.removeProperty('animation-iteration-count'); - element.style.removeProperty('animation-delay'); - element.style.removeProperty('animation-play-state'); - }); - - this.initialized = false; + this.cleanUpElements(); } private initializeAnimation(): void { @@ -424,14 +433,14 @@ export class Animation { } playStep(step: number): Animation { - if (!this.initialized) { - this.initializeAnimation(); - } - this.childAnimations.forEach(animation => { animation.playStep(step); }); + if (!this.initialized) { + this.initializeAnimation(); + } + this.pause(); if (this.getDuration() !== undefined) { @@ -446,11 +455,11 @@ export class Animation { } pause(): Animation { - if (this.initialized) { - this.childAnimations.forEach(animation => { - animation.pause(); - }); + this.childAnimations.forEach(animation => { + animation.pause(); + }); + if (this.initialized) { this.elements.forEach(element => { (element as HTMLElement).style.animationPlayState = 'paused'; }); @@ -460,18 +469,31 @@ export class Animation { } play(): Animation { - if (!this.initialized) { - this.initializeAnimation(); - } - this.childAnimations.forEach(animation => { animation.play(); }); + if (!this.initialized) { + this.initializeAnimation(); + } + this.elements.forEach(element => { (element as HTMLElement).style.animationPlayState = 'running'; }); return this; } + + stop(): Animation { + this.childAnimations.forEach(animation => { + animation.stop(); + }); + + if (this.initialized) { + this.cleanUp(); + this.initialized = false; + } + + return this; + } } diff --git a/core/src/utils/animation/test/animation.spec.ts b/core/src/utils/animation/test/animation.spec.ts index 4f6e1929ad..972e1a6d1e 100644 --- a/core/src/utils/animation/test/animation.spec.ts +++ b/core/src/utils/animation/test/animation.spec.ts @@ -164,6 +164,32 @@ describe('Animation Class', () => { expect(animation.beforeRemoveClasses.length).toEqual(0); }); + it('should apply all "before" styles', () => { + const el = document.createElement('div'); + el.classList.add('hello', 'world'); + el.style.setProperty('opacity', "0.5"); + + animation + .addElement(el) + .beforeAddClass(['ionic', 'framework']) + .beforeStyles({ 'background': 'blue' }) + .beforeClearStyles(['opacity']) + .beforeRemoveClass('hello'); + + expect(el.style.getPropertyValue('opacity')).toEqual("0.5"); + expect(el.classList.contains('hello')).toEqual(true); + expect(el.classList.contains('world')).toEqual(true); + + animation.play(); + + expect(el.style.getPropertyValue('opacity')).toEqual(""); + expect(el.style.getPropertyValue('background')).toEqual('blue'); + expect(el.classList.contains('hello')).toEqual(false); + expect(el.classList.contains('world')).toEqual(true); + expect(el.classList.contains('ionic')).toEqual(true); + expect(el.classList.contains('framework')).toEqual(true); + }); + it('should register all "after" styles', () => { animation.afterStyles({ 'background': 'red', 'opacity': 1 }); expect(Object.keys(animation.afterStylesValue).length).toEqual(2); @@ -197,6 +223,47 @@ describe('Animation Class', () => { expect(animation.afterAddClasses.length).toEqual(0); expect(animation.afterRemoveClasses.length).toEqual(0); + }); + + it('should apply all "after" styles', async () => { + const el = document.createElement('div'); + el.classList.add('hello', 'world'); + el.style.setProperty('opacity', "0.5"); + + animation + .name('my-animation') + .addElement(el) + .duration(500) + .keyframes([ + { transform: 'scale(1) rotate(0deg)', opacity: 1, offset: 0 }, + { transform: 'scale(0.5) rotate(-45deg)', opacity: 0.5, offset: 0.5 }, + { transform: 'scale(1) rotate(0deg)', opacity: 1, offset: 1 } + ]) + .afterAddClass(['ionic', 'framework']) + .afterStyles({ 'background': 'blue' }) + .afterClearStyles(['opacity']) + .afterRemoveClass('hello'); + + expect(el.style.getPropertyValue('opacity')).toEqual("0.5"); + expect(el.classList.contains('hello')).toEqual(true); + expect(el.classList.contains('world')).toEqual(true); + + animation.play(); + + /** + * Animations don't run in spec tests + * so we have to fake the end of the animation + */ + const ev = new CustomEvent('animationend'); + el.dispatchEvent(ev); + + expect(el.style.getPropertyValue('opacity')).toEqual(""); + expect(el.style.getPropertyValue('background')).toEqual('blue'); + expect(el.classList.contains('hello')).toEqual(false); + expect(el.classList.contains('world')).toEqual(true); + expect(el.classList.contains('ionic')).toEqual(true); + expect(el.classList.contains('framework')).toEqual(true); + }); }); diff --git a/core/src/utils/animation/test/multiple/index.html b/core/src/utils/animation/test/multiple/index.html index 8f4f4a9096..0222320980 100644 --- a/core/src/utils/animation/test/multiple/index.html +++ b/core/src/utils/animation/test/multiple/index.html @@ -80,13 +80,22 @@ }); rootAnimation.addAnimation([animationA, animationB, animationC]); - rootAnimation.play(); - - console.log(rootAnimation); - + document.querySelector('.play').addEventListener('click', () => { - rootAnimation.play(); - }); + rootAnimation.play(); + }); + + document.querySelector('.pause').addEventListener('click', () => { + rootAnimation.pause(); + }); + + document.querySelector('.destroy').addEventListener('click', () => { + rootAnimation.destroy(); + }); + + document.querySelector('.stop').addEventListener('click', () => { + rootAnimation.stop(); + });