fix(animations): repair flicker issues with WA polyfill (#16937)

Fixes #16919
Fixes #16918
This commit is contained in:
Matias Niemelä 2017-05-22 16:57:16 -07:00 committed by Chuck Jazdzewski
parent 08dfe91b95
commit e7d9fd8056
7 changed files with 85 additions and 13 deletions

View File

@ -5,6 +5,8 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {dashCaseToCamelCase} from '../../util';
import {AnimationStyleNormalizer} from './animation_style_normalizer';
export class WebAnimationsStyleNormalizer extends AnimationStyleNormalizer {
@ -41,8 +43,3 @@ function makeBooleanMap(keys: string[]): {[key: string]: boolean} {
keys.forEach(key => map[key] = true);
return map;
}
const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
export function dashCaseToCamelCase(input: string): string {
return input.replace(DASH_CASE_REGEXP, (...m: any[]) => m[1].toUpperCase());
}

View File

@ -997,9 +997,8 @@ export class TransitionAnimationEngine {
});
allConsumedElements.forEach(element => addClass(element, NG_ANIMATING_CLASSNAME));
const player = optimizeGroupPlayer(allNewPlayers);
player.onDone(() => {
player.onDestroy(() => {
allConsumedElements.forEach(element => removeClass(element, NG_ANIMATING_CLASSNAME));
setStyles(rootElement, instruction.toStyles);
});

View File

@ -53,6 +53,11 @@ export class WebAnimationsPlayer implements AnimationPlayer {
}
init(): void {
this._buildPlayer();
this._preparePlayerBeforeStart();
}
private _buildPlayer(): void {
if (this._initialized) return;
this._initialized = true;
@ -82,14 +87,16 @@ export class WebAnimationsPlayer implements AnimationPlayer {
this._player = this._triggerWebAnimation(this.element, keyframes, this.options);
this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : {};
this._player.addEventListener('finish', () => this._onFinish());
}
private _preparePlayerBeforeStart() {
// this is required so that the player doesn't start to animate right away
if (this._delay) {
this._resetDomPlayerState();
} else {
this._player.pause();
}
this._player.addEventListener('finish', () => this._onFinish());
}
/** @internal */
@ -108,7 +115,7 @@ export class WebAnimationsPlayer implements AnimationPlayer {
onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); }
play(): void {
this.init();
this._buildPlayer();
if (!this.hasStarted()) {
this._onStartFns.forEach(fn => fn());
this._onStartFns = [];

View File

@ -123,16 +123,18 @@ export function copyStyles(
export function setStyles(element: any, styles: ɵStyleData) {
if (element['style']) {
Object.keys(styles).forEach(prop => element.style[prop] = styles[prop]);
Object.keys(styles).forEach(prop => {
const camelProp = dashCaseToCamelCase(prop);
element.style[camelProp] = styles[prop];
});
}
}
export function eraseStyles(element: any, styles: ɵStyleData) {
if (element['style']) {
Object.keys(styles).forEach(prop => {
// IE requires '' instead of null
// see https://github.com/angular/angular/issues/7916
element.style[prop] = '';
const camelProp = dashCaseToCamelCase(prop);
element.style[camelProp] = '';
});
}
}
@ -206,3 +208,8 @@ export function mergeAnimationOptions(
}
return destination;
}
const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
export function dashCaseToCamelCase(input: string): string {
return input.replace(DASH_CASE_REGEXP, (...m: any[]) => m[1].toUpperCase());
}

View File

@ -0,0 +1,62 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {DOMAnimation} from '../../../src/render/web_animations/dom_animation';
import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animations_player';
export function main() {
let element: any;
let innerPlayer: MockDomAnimation|null = null;
beforeEach(() => {
element = {};
element['animate'] = () => { return innerPlayer = new MockDomAnimation(); };
});
describe('WebAnimationsPlayer tests', () => {
it('should automatically pause the player when created and initialized', () => {
const keyframes = [
{opacity: 0, offset: 0},
{opacity: 1, offset: 1},
];
const player = new WebAnimationsPlayer(element, keyframes, {duration: 1000});
player.init();
const p = innerPlayer !;
expect(p.log).toEqual(['pause']);
player.play();
expect(p.log).toEqual(['pause', 'play']);
});
it('should not pause the player if created and started before initialized', () => {
const keyframes = [
{opacity: 0, offset: 0},
{opacity: 1, offset: 1},
];
const player = new WebAnimationsPlayer(element, keyframes, {duration: 1000});
player.play();
const p = innerPlayer !;
expect(p.log).toEqual(['play']);
});
});
}
class MockDomAnimation implements DOMAnimation {
log: string[] = [];
cancel(): void { this.log.push('cancel'); }
play(): void { this.log.push('play'); }
pause(): void { this.log.push('pause'); }
finish(): void { this.log.push('finish'); }
onfinish: Function = () => {};
position: number = 0;
currentTime: number = 0;
addEventListener(eventName: string, handler: (event: any) => any): any {}
dispatchEvent(eventName: string): any {}
}