mirror of
				https://github.com/NativeScript/NativeScript.git
				synced 2025-11-04 12:58:38 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { CssAnimationProperty } from '../core/properties';
 | 
						|
 | 
						|
import { KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo, UnparsedKeyframe } from '../animation/keyframe-animation';
 | 
						|
import { timeConverter, animationTimingFunctionConverter } from '../styling/converters';
 | 
						|
 | 
						|
import { transformConverter } from '../styling/style-properties';
 | 
						|
 | 
						|
const ANIMATION_PROPERTY_HANDLERS = Object.freeze({
 | 
						|
	'animation-name': (info: any, value: any) => (info.name = value),
 | 
						|
	'animation-duration': (info: any, value: any) => (info.duration = timeConverter(value)),
 | 
						|
	'animation-delay': (info: any, value: any) => (info.delay = timeConverter(value)),
 | 
						|
	'animation-timing-function': (info: any, value: any) => (info.curve = animationTimingFunctionConverter(value)),
 | 
						|
	'animation-iteration-count': (info: any, value: any) => (info.iterations = value === 'infinite' ? Number.MAX_VALUE : parseFloat(value)),
 | 
						|
	'animation-direction': (info: any, value: any) => (info.isReverse = value === 'reverse'),
 | 
						|
	'animation-fill-mode': (info: any, value: any) => (info.isForwards = value === 'forwards'),
 | 
						|
});
 | 
						|
 | 
						|
export class CssAnimationParser {
 | 
						|
	public static keyframeAnimationsFromCSSDeclarations(declarations: KeyframeDeclaration[]): KeyframeAnimationInfo[] {
 | 
						|
		if (declarations === null || declarations === undefined) {
 | 
						|
			return undefined;
 | 
						|
		}
 | 
						|
 | 
						|
		const animations = new Array<KeyframeAnimationInfo>();
 | 
						|
		let animationInfo: KeyframeAnimationInfo = undefined;
 | 
						|
 | 
						|
		declarations.forEach(({ property, value }) => {
 | 
						|
			if (property === 'animation') {
 | 
						|
				keyframeAnimationsFromCSSProperty(value, animations);
 | 
						|
			} else {
 | 
						|
				const propertyHandler = ANIMATION_PROPERTY_HANDLERS[property];
 | 
						|
				if (propertyHandler) {
 | 
						|
					if (animationInfo === undefined) {
 | 
						|
						animationInfo = new KeyframeAnimationInfo();
 | 
						|
						animations.push(animationInfo);
 | 
						|
					}
 | 
						|
					propertyHandler(animationInfo, value);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		});
 | 
						|
 | 
						|
		return animations.length === 0 ? undefined : animations;
 | 
						|
	}
 | 
						|
 | 
						|
	public static keyframesArrayFromCSS(keyframes: UnparsedKeyframe[]): KeyframeInfo[] {
 | 
						|
		const parsedKeyframes = new Array<KeyframeInfo>();
 | 
						|
		for (const keyframe of keyframes) {
 | 
						|
			const declarations = parseKeyframeDeclarations(keyframe.declarations);
 | 
						|
			for (let time of keyframe.values) {
 | 
						|
				if (time === 'from') {
 | 
						|
					time = 0;
 | 
						|
				} else if (time === 'to') {
 | 
						|
					time = 1;
 | 
						|
				} else {
 | 
						|
					time = parseFloat(time) / 100;
 | 
						|
					if (time < 0) {
 | 
						|
						time = 0;
 | 
						|
					}
 | 
						|
					if (time > 100) {
 | 
						|
						time = 100;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				let current = parsedKeyframes[time];
 | 
						|
				if (current === undefined) {
 | 
						|
					current = <KeyframeInfo>{};
 | 
						|
					current.duration = time;
 | 
						|
					parsedKeyframes[time] = current;
 | 
						|
				}
 | 
						|
				for (const declaration of keyframe.declarations) {
 | 
						|
					if (declaration.property === 'animation-timing-function') {
 | 
						|
						current.curve = animationTimingFunctionConverter(declaration.value);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				current.declarations = declarations;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		const array = [];
 | 
						|
		for (const parsedKeyframe in parsedKeyframes) {
 | 
						|
			array.push(parsedKeyframes[parsedKeyframe]);
 | 
						|
		}
 | 
						|
		array.sort(function (a, b) {
 | 
						|
			return a.duration - b.duration;
 | 
						|
		});
 | 
						|
 | 
						|
		return array;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
function keyframeAnimationsFromCSSProperty(value: any, animations: KeyframeAnimationInfo[]) {
 | 
						|
	if (typeof value === 'string') {
 | 
						|
		const values = value.split(/[,]+/);
 | 
						|
		for (const parsedValue of values) {
 | 
						|
			const animationInfo = new KeyframeAnimationInfo();
 | 
						|
			const arr = (<string>parsedValue).trim().split(/[ ]+/);
 | 
						|
 | 
						|
			if (arr.length > 0) {
 | 
						|
				animationInfo.name = arr[0];
 | 
						|
			}
 | 
						|
			if (arr.length > 1) {
 | 
						|
				animationInfo.duration = timeConverter(arr[1]);
 | 
						|
			}
 | 
						|
			if (arr.length > 2) {
 | 
						|
				animationInfo.curve = animationTimingFunctionConverter(arr[2]);
 | 
						|
			}
 | 
						|
			if (arr.length > 3) {
 | 
						|
				animationInfo.delay = timeConverter(arr[3]);
 | 
						|
			}
 | 
						|
			if (arr.length > 4) {
 | 
						|
				animationInfo.iterations = parseInt(arr[4]);
 | 
						|
			}
 | 
						|
			if (arr.length > 5) {
 | 
						|
				animationInfo.isReverse = arr[4] === 'reverse';
 | 
						|
			}
 | 
						|
			if (arr.length > 6) {
 | 
						|
				animationInfo.isForwards = arr[5] === 'forwards';
 | 
						|
			}
 | 
						|
			if (arr.length > 7) {
 | 
						|
				throw new Error('Invalid value for animation: ' + value);
 | 
						|
			}
 | 
						|
			animations.push(animationInfo);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
export function parseKeyframeDeclarations(unparsedKeyframeDeclarations: KeyframeDeclaration[]): KeyframeDeclaration[] {
 | 
						|
	const declarations = unparsedKeyframeDeclarations.reduce((declarations, { property: unparsedProperty, value: unparsedValue }) => {
 | 
						|
		const property = CssAnimationProperty._getByCssName(unparsedProperty);
 | 
						|
 | 
						|
		if (typeof unparsedProperty === 'string' && property && property._valueConverter) {
 | 
						|
			declarations[property.name] = property._valueConverter(<string>unparsedValue);
 | 
						|
		} else if (typeof unparsedValue === 'string' && unparsedProperty === 'transform') {
 | 
						|
			const transformations = transformConverter(unparsedValue);
 | 
						|
			Object.assign(declarations, transformations);
 | 
						|
		}
 | 
						|
 | 
						|
		return declarations;
 | 
						|
	}, {});
 | 
						|
 | 
						|
	return Object.keys(declarations).map((property) => ({
 | 
						|
		property,
 | 
						|
		value: declarations[property],
 | 
						|
	}));
 | 
						|
}
 |