parent
4f56a01b3b
commit
bffa2cb59b
|
@ -2,7 +2,8 @@ import {
|
|||
DateWrapper,
|
||||
StringWrapper,
|
||||
RegExpWrapper,
|
||||
NumberWrapper
|
||||
NumberWrapper,
|
||||
isPresent
|
||||
} from 'angular2/src/core/facade/lang';
|
||||
import {Math} from 'angular2/src/core/facade/math';
|
||||
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 */
|
||||
completed: boolean = false;
|
||||
|
||||
private _stringPrefix: string = '';
|
||||
|
||||
/** total amount of time that the animation should take including delay */
|
||||
get totalTime(): number {
|
||||
let delay = this.computedDelay != null ? this.computedDelay : 0;
|
||||
|
@ -47,6 +50,7 @@ export class Animation {
|
|||
constructor(public element: HTMLElement, public data: CssAnimationOptions,
|
||||
public browserDetails: BrowserDetails) {
|
||||
this.startTime = DateWrapper.toMillis(DateWrapper.now());
|
||||
this._stringPrefix = DOM.getAnimationPrefix();
|
||||
this.setup();
|
||||
this.wait(timestamp => this.start());
|
||||
}
|
||||
|
@ -77,11 +81,14 @@ export class Animation {
|
|||
if (this.data.toStyles != null) this.applyStyles(this.data.toStyles);
|
||||
var computedStyles = DOM.getComputedStyle(this.element);
|
||||
this.computedDelay =
|
||||
Math.max(this.parseDurationString(computedStyles.getPropertyValue('transition-delay')),
|
||||
this.parseDurationString(this.element.style.getPropertyValue('transition-delay')));
|
||||
this.computedDuration = Math.max(
|
||||
this.parseDurationString(computedStyles.getPropertyValue('transition-duration')),
|
||||
this.parseDurationString(this.element.style.getPropertyValue('transition-duration')));
|
||||
Math.max(this.parseDurationString(
|
||||
computedStyles.getPropertyValue(this._stringPrefix + 'transition-delay')),
|
||||
this.parseDurationString(
|
||||
this.element.style.getPropertyValue(this._stringPrefix + 'transition-delay')));
|
||||
this.computedDuration = Math.max(this.parseDurationString(computedStyles.getPropertyValue(
|
||||
this._stringPrefix + 'transition-duration')),
|
||||
this.parseDurationString(this.element.style.getPropertyValue(
|
||||
this._stringPrefix + 'transition-duration')));
|
||||
this.addEvents();
|
||||
}
|
||||
|
||||
|
@ -91,7 +98,12 @@ export class Animation {
|
|||
*/
|
||||
applyStyles(styles: StringMap<string, any>): void {
|
||||
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 {
|
||||
if (this.totalTime > 0) {
|
||||
this.eventClearFunctions.push(DOM.onAndCancel(
|
||||
this.element, 'transitionend', (event: any) => this.handleAnimationEvent(event)));
|
||||
this.element, DOM.getTransitionEnd(), (event: any) => this.handleAnimationEvent(event)));
|
||||
} else {
|
||||
this.handleAnimationCompleted();
|
||||
}
|
||||
|
|
|
@ -139,4 +139,7 @@ export class DomAdapter {
|
|||
requestAnimationFrame(callback): number { throw _abstract(); }
|
||||
cancelAnimationFrame(id) { 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 {isPresent, isFunction} from 'angular2/src/core/facade/lang';
|
||||
import {ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {isPresent, isFunction, StringWrapper} from 'angular2/src/core/facade/lang';
|
||||
import {DomAdapter} from './dom_adapter';
|
||||
|
||||
/**
|
||||
* Provides DOM operations in any browser environment.
|
||||
*/
|
||||
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(); }
|
||||
resolveAndSetHref(el: HTMLAnchorElement, baseUrl: string, href: string) {
|
||||
el.href = href == null ? baseUrl : baseUrl + '/../' + href;
|
||||
|
@ -37,4 +70,11 @@ export class GenericBrowserDomAdapter extends DomAdapter {
|
|||
supportsNativeShadowDOM(): boolean {
|
||||
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() {
|
||||
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); }
|
||||
cancelAnimationFrame(id: number) { clearTimeout(id); }
|
||||
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
|
||||
|
|
|
@ -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 {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
|
||||
export function main() {
|
||||
describe("AnimationBuilder", () => {
|
||||
|
@ -54,8 +55,13 @@ export function main() {
|
|||
var runner = animateCss.start(element);
|
||||
runner.flush();
|
||||
|
||||
if (DOM.supportsAnimation()) {
|
||||
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 => {
|
||||
|
@ -71,12 +77,18 @@ export function main() {
|
|||
|
||||
it('should support duration and delay defined in CSS', inject([AnimationBuilder], (animate) => {
|
||||
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);
|
||||
runner.flush();
|
||||
|
||||
expect(runner.computedDuration).toEqual(500);
|
||||
expect(runner.computedDelay).toEqual(250);
|
||||
if (DOM.supportsAnimation()) {
|
||||
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) => {
|
||||
|
@ -108,11 +120,15 @@ export function main() {
|
|||
|
||||
runner.flush();
|
||||
|
||||
if (DOM.supportsAnimation()) {
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
|
||||
runner.handleAnimationCompleted();
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
} else {
|
||||
expect(callback).toHaveBeenCalled();
|
||||
}
|
||||
}));
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue