parent
4f56a01b3b
commit
bffa2cb59b
|
@ -2,7 +2,8 @@ import {
|
||||||
DateWrapper,
|
DateWrapper,
|
||||||
StringWrapper,
|
StringWrapper,
|
||||||
RegExpWrapper,
|
RegExpWrapper,
|
||||||
NumberWrapper
|
NumberWrapper,
|
||||||
|
isPresent
|
||||||
} from 'angular2/src/core/facade/lang';
|
} from 'angular2/src/core/facade/lang';
|
||||||
import {Math} from 'angular2/src/core/facade/math';
|
import {Math} from 'angular2/src/core/facade/math';
|
||||||
import {camelCaseToDashCase} from 'angular2/src/core/render/dom/util';
|
import {camelCaseToDashCase} from 'angular2/src/core/render/dom/util';
|
||||||
|
@ -31,6 +32,8 @@ export class Animation {
|
||||||
/** flag used to track whether or not the animation has finished */
|
/** flag used to track whether or not the animation has finished */
|
||||||
completed: boolean = false;
|
completed: boolean = false;
|
||||||
|
|
||||||
|
private _stringPrefix: string = '';
|
||||||
|
|
||||||
/** total amount of time that the animation should take including delay */
|
/** total amount of time that the animation should take including delay */
|
||||||
get totalTime(): number {
|
get totalTime(): number {
|
||||||
let delay = this.computedDelay != null ? this.computedDelay : 0;
|
let delay = this.computedDelay != null ? this.computedDelay : 0;
|
||||||
|
@ -47,6 +50,7 @@ export class Animation {
|
||||||
constructor(public element: HTMLElement, public data: CssAnimationOptions,
|
constructor(public element: HTMLElement, public data: CssAnimationOptions,
|
||||||
public browserDetails: BrowserDetails) {
|
public browserDetails: BrowserDetails) {
|
||||||
this.startTime = DateWrapper.toMillis(DateWrapper.now());
|
this.startTime = DateWrapper.toMillis(DateWrapper.now());
|
||||||
|
this._stringPrefix = DOM.getAnimationPrefix();
|
||||||
this.setup();
|
this.setup();
|
||||||
this.wait(timestamp => this.start());
|
this.wait(timestamp => this.start());
|
||||||
}
|
}
|
||||||
|
@ -77,11 +81,14 @@ export class Animation {
|
||||||
if (this.data.toStyles != null) this.applyStyles(this.data.toStyles);
|
if (this.data.toStyles != null) this.applyStyles(this.data.toStyles);
|
||||||
var computedStyles = DOM.getComputedStyle(this.element);
|
var computedStyles = DOM.getComputedStyle(this.element);
|
||||||
this.computedDelay =
|
this.computedDelay =
|
||||||
Math.max(this.parseDurationString(computedStyles.getPropertyValue('transition-delay')),
|
Math.max(this.parseDurationString(
|
||||||
this.parseDurationString(this.element.style.getPropertyValue('transition-delay')));
|
computedStyles.getPropertyValue(this._stringPrefix + 'transition-delay')),
|
||||||
this.computedDuration = Math.max(
|
this.parseDurationString(
|
||||||
this.parseDurationString(computedStyles.getPropertyValue('transition-duration')),
|
this.element.style.getPropertyValue(this._stringPrefix + 'transition-delay')));
|
||||||
this.parseDurationString(this.element.style.getPropertyValue('transition-duration')));
|
this.computedDuration = Math.max(this.parseDurationString(computedStyles.getPropertyValue(
|
||||||
|
this._stringPrefix + 'transition-duration')),
|
||||||
|
this.parseDurationString(this.element.style.getPropertyValue(
|
||||||
|
this._stringPrefix + 'transition-duration')));
|
||||||
this.addEvents();
|
this.addEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +98,12 @@ export class Animation {
|
||||||
*/
|
*/
|
||||||
applyStyles(styles: StringMap<string, any>): void {
|
applyStyles(styles: StringMap<string, any>): void {
|
||||||
StringMapWrapper.forEach(styles, (value, key) => {
|
StringMapWrapper.forEach(styles, (value, key) => {
|
||||||
DOM.setStyle(this.element, camelCaseToDashCase(key), value.toString());
|
var dashCaseKey = camelCaseToDashCase(key);
|
||||||
|
if (isPresent(DOM.getStyle(this.element, dashCaseKey))) {
|
||||||
|
DOM.setStyle(this.element, dashCaseKey, value.toString());
|
||||||
|
} else {
|
||||||
|
DOM.setStyle(this.element, this._stringPrefix + dashCaseKey, value.toString());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +129,7 @@ export class Animation {
|
||||||
addEvents(): void {
|
addEvents(): void {
|
||||||
if (this.totalTime > 0) {
|
if (this.totalTime > 0) {
|
||||||
this.eventClearFunctions.push(DOM.onAndCancel(
|
this.eventClearFunctions.push(DOM.onAndCancel(
|
||||||
this.element, 'transitionend', (event: any) => this.handleAnimationEvent(event)));
|
this.element, DOM.getTransitionEnd(), (event: any) => this.handleAnimationEvent(event)));
|
||||||
} else {
|
} else {
|
||||||
this.handleAnimationCompleted();
|
this.handleAnimationCompleted();
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,4 +139,7 @@ export class DomAdapter {
|
||||||
requestAnimationFrame(callback): number { throw _abstract(); }
|
requestAnimationFrame(callback): number { throw _abstract(); }
|
||||||
cancelAnimationFrame(id) { throw _abstract(); }
|
cancelAnimationFrame(id) { throw _abstract(); }
|
||||||
performanceNow(): number { throw _abstract(); }
|
performanceNow(): number { throw _abstract(); }
|
||||||
|
getAnimationPrefix(): string { throw _abstract(); }
|
||||||
|
getTransitionEnd(): string { throw _abstract(); }
|
||||||
|
supportsAnimation(): boolean { throw _abstract(); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,44 @@
|
||||||
import {ListWrapper} from 'angular2/src/core/facade/collection';
|
import {ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||||
import {isPresent, isFunction} from 'angular2/src/core/facade/lang';
|
import {isPresent, isFunction, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||||
import {DomAdapter} from './dom_adapter';
|
import {DomAdapter} from './dom_adapter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides DOM operations in any browser environment.
|
* Provides DOM operations in any browser environment.
|
||||||
*/
|
*/
|
||||||
export class GenericBrowserDomAdapter extends DomAdapter {
|
export class GenericBrowserDomAdapter extends DomAdapter {
|
||||||
|
private _animationPrefix: string = null;
|
||||||
|
private _transitionEnd: string = null;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
try {
|
||||||
|
var element = this.createElement('div', this.defaultDoc());
|
||||||
|
if (isPresent(this.getStyle(element, 'animationName'))) {
|
||||||
|
this._animationPrefix = '';
|
||||||
|
} else {
|
||||||
|
var domPrefixes = ['Webkit', 'Moz', 'O', 'ms'];
|
||||||
|
for (var i = 0; i < domPrefixes.length; i++) {
|
||||||
|
if (isPresent(this.getStyle(element, domPrefixes[i] + 'AnimationName'))) {
|
||||||
|
this._animationPrefix = '-' + StringWrapper.toLowerCase(domPrefixes[i]) + '-';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var transEndEventNames = {
|
||||||
|
WebkitTransition: 'webkitTransitionEnd',
|
||||||
|
MozTransition: 'transitionend',
|
||||||
|
OTransition: 'oTransitionEnd otransitionend',
|
||||||
|
transition: 'transitionend'
|
||||||
|
};
|
||||||
|
StringMapWrapper.forEach(transEndEventNames, (value, key) => {
|
||||||
|
if (isPresent(this.getStyle(element, key))) {
|
||||||
|
this._transitionEnd = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this._animationPrefix = null;
|
||||||
|
this._transitionEnd = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
getDistributedNodes(el: HTMLElement): Node[] { return (<any>el).getDistributedNodes(); }
|
getDistributedNodes(el: HTMLElement): Node[] { return (<any>el).getDistributedNodes(); }
|
||||||
resolveAndSetHref(el: HTMLAnchorElement, baseUrl: string, href: string) {
|
resolveAndSetHref(el: HTMLAnchorElement, baseUrl: string, href: string) {
|
||||||
el.href = href == null ? baseUrl : baseUrl + '/../' + href;
|
el.href = href == null ? baseUrl : baseUrl + '/../' + href;
|
||||||
|
@ -37,4 +70,11 @@ export class GenericBrowserDomAdapter extends DomAdapter {
|
||||||
supportsNativeShadowDOM(): boolean {
|
supportsNativeShadowDOM(): boolean {
|
||||||
return isFunction((<any>this.defaultDoc().body).createShadowRoot);
|
return isFunction((<any>this.defaultDoc().body).createShadowRoot);
|
||||||
}
|
}
|
||||||
|
getAnimationPrefix(): string {
|
||||||
|
return isPresent(this._animationPrefix) ? this._animationPrefix : "";
|
||||||
|
}
|
||||||
|
getTransitionEnd(): string { return isPresent(this._transitionEnd) ? this._transitionEnd : ""; }
|
||||||
|
supportsAnimation(): boolean {
|
||||||
|
return isPresent(this._animationPrefix) && isPresent(this._transitionEnd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -435,4 +435,16 @@ class Html5LibDomAdapter implements DomAdapter {
|
||||||
performanceNow() {
|
performanceNow() {
|
||||||
throw 'not implemented';
|
throw 'not implemented';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAnimationPrefix() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransitionEnd() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
supportsAnimation() {
|
||||||
|
throw 'not implemented';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -552,6 +552,9 @@ export class Parse5DomAdapter extends DomAdapter {
|
||||||
requestAnimationFrame(callback): number { return setTimeout(callback, 0); }
|
requestAnimationFrame(callback): number { return setTimeout(callback, 0); }
|
||||||
cancelAnimationFrame(id: number) { clearTimeout(id); }
|
cancelAnimationFrame(id: number) { clearTimeout(id); }
|
||||||
performanceNow(): number { return DateWrapper.toMillis(DateWrapper.now()); }
|
performanceNow(): number { return DateWrapper.toMillis(DateWrapper.now()); }
|
||||||
|
getAnimationPrefix(): string { return ''; }
|
||||||
|
getTransitionEnd(): string { return 'transitionend'; }
|
||||||
|
supportsAnimation(): boolean { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: build a proper list, this one is all the keys of a HTMLInputElement
|
// TODO: build a proper list, this one is all the keys of a HTMLInputElement
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {el, describe, it, expect, inject, SpyObject} from 'angular2/test_lib';
|
import {el, describe, it, iit, expect, inject, SpyObject} from 'angular2/test_lib';
|
||||||
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
|
||||||
|
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe("AnimationBuilder", () => {
|
describe("AnimationBuilder", () => {
|
||||||
|
@ -54,8 +55,13 @@ export function main() {
|
||||||
var runner = animateCss.start(element);
|
var runner = animateCss.start(element);
|
||||||
runner.flush();
|
runner.flush();
|
||||||
|
|
||||||
expect(runner.computedDelay).toBe(100);
|
if (DOM.supportsAnimation()) {
|
||||||
expect(runner.computedDuration).toBe(200);
|
expect(runner.computedDelay).toBe(100);
|
||||||
|
expect(runner.computedDuration).toBe(200);
|
||||||
|
} else {
|
||||||
|
expect(runner.computedDelay).toBe(0);
|
||||||
|
expect(runner.computedDuration).toBe(0);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should support from styles', inject([AnimationBuilder], animate => {
|
it('should support from styles', inject([AnimationBuilder], animate => {
|
||||||
|
@ -71,12 +77,18 @@ export function main() {
|
||||||
|
|
||||||
it('should support duration and delay defined in CSS', inject([AnimationBuilder], (animate) => {
|
it('should support duration and delay defined in CSS', inject([AnimationBuilder], (animate) => {
|
||||||
var animateCss = animate.css();
|
var animateCss = animate.css();
|
||||||
var element = el('<div style="transition: 0.5s ease 250ms;"></div>');
|
var element =
|
||||||
|
el(`<div style="${DOM.getAnimationPrefix()}transition: 0.5s ease 250ms;"></div>`);
|
||||||
var runner = animateCss.start(element);
|
var runner = animateCss.start(element);
|
||||||
runner.flush();
|
runner.flush();
|
||||||
|
|
||||||
expect(runner.computedDuration).toEqual(500);
|
if (DOM.supportsAnimation()) {
|
||||||
expect(runner.computedDelay).toEqual(250);
|
expect(runner.computedDelay).toBe(250);
|
||||||
|
expect(runner.computedDuration).toBe(500);
|
||||||
|
} else {
|
||||||
|
expect(runner.computedDelay).toEqual(0);
|
||||||
|
expect(runner.computedDuration).toEqual(0);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should add classes', inject([AnimationBuilder], (animate) => {
|
it('should add classes', inject([AnimationBuilder], (animate) => {
|
||||||
|
@ -108,11 +120,15 @@ export function main() {
|
||||||
|
|
||||||
runner.flush();
|
runner.flush();
|
||||||
|
|
||||||
expect(callback).not.toHaveBeenCalled();
|
if (DOM.supportsAnimation()) {
|
||||||
|
expect(callback).not.toHaveBeenCalled();
|
||||||
|
|
||||||
runner.handleAnimationCompleted();
|
runner.handleAnimationCompleted();
|
||||||
|
|
||||||
expect(callback).toHaveBeenCalled();
|
expect(callback).toHaveBeenCalled();
|
||||||
|
} else {
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue