* Fixed issue [#893](https://github.com/jakubpawlowicz/clean-css/issues/893) - `inline: false` as alias to `inline: 'none'`.
* Fixed issue [#890](https://github.com/jakubpawlowicz/clean-css/issues/890) - adds toggle to disable empty tokens removal.
* Fixed issue [#886](https://github.com/jakubpawlowicz/clean-css/issues/886) - better multi pseudo class / element merging.
+* Fixed issue [#860](https://github.com/jakubpawlowicz/clean-css/issues/860) - adds `animation` property optimizer.
* Fixed issue [#755](https://github.com/jakubpawlowicz/clean-css/issues/755) - adds custom handling of remote requests.
* Fixed issue [#254](https://github.com/jakubpawlowicz/clean-css/issues/254) - adds `font` property optimizer.
* new `font` shorthand and `font-*` longhand optimizers;
* removal of `optimizeFont` flag in level 1 optimizations due to new `font` shorthand optimizer;
* `skipProperties` flag in level 2 optimizations controlling which properties won't be optimized;
+* new `animation` shorthand and `animation-*` longhand optimizers;
## Constructor options
};
}
+function animation(property, compactable, validator) {
+ var duration = _wrapDefault('animation-duration', property, compactable);
+ var timing = _wrapDefault('animation-timing-function', property, compactable);
+ var delay = _wrapDefault('animation-delay', property, compactable);
+ var iteration = _wrapDefault('animation-iteration-count', property, compactable);
+ var direction = _wrapDefault('animation-direction', property, compactable);
+ var fill = _wrapDefault('animation-fill-mode', property, compactable);
+ var play = _wrapDefault('animation-play-state', property, compactable);
+ var name = _wrapDefault('animation-name', property, compactable);
+ var components = [duration, timing, delay, iteration, direction, fill, play, name];
+ var values = property.value;
+ var value;
+ var durationSet = false;
+ var timingSet = false;
+ var delaySet = false;
+ var iterationSet = false;
+ var directionSet = false;
+ var fillSet = false;
+ var playSet = false;
+ var nameSet = false;
+ var i;
+ var l;
+
+ if (property.value.length == 1 && property.value[0][1] == 'inherit') {
+ duration.value = timing.value = delay.value = iteration.value = direction.value = fill.value = play.value = name.value = property.value;
+ return components;
+ }
+
+ if (values.length > 1 && _anyIsInherit(values)) {
+ throw new InvalidPropertyError('Invalid animation values at ' + formatPosition(values[0][2][0]) + '. Ignoring.');
+ }
+
+ for (i = 0, l = values.length; i < l; i++) {
+ value = values[i];
+
+ if (validator.isTime(value[1]) && !durationSet) {
+ duration.value = [value];
+ durationSet = true;
+ } else if (validator.isTime(value[1]) && !delaySet) {
+ delay.value = [value];
+ delaySet = true;
+ } else if ((validator.isGlobal(value[1]) || validator.isAnimationTimingFunction(value[1])) && !timingSet) {
+ timing.value = [value];
+ timingSet = true;
+ } else if ((validator.isAnimationIterationCountKeyword(value[1]) || validator.isPositiveNumber(value[1])) && !iterationSet) {
+ iteration.value = [value];
+ iterationSet = true;
+ } else if (validator.isAnimationDirectionKeyword(value[1]) && !directionSet) {
+ direction.value = [value];
+ directionSet = true;
+ } else if (validator.isAnimationFillModeKeyword(value[1]) && !fillSet) {
+ fill.value = [value];
+ fillSet = true;
+ } else if (validator.isAnimationPlayStateKeyword(value[1]) && !playSet) {
+ play.value = [value];
+ playSet = true;
+ } else if ((validator.isAnimationNameKeyword(value[1]) || validator.isIdentifier(value[1])) && !nameSet) {
+ name.value = [value];
+ nameSet = true;
+ } else {
+ throw new InvalidPropertyError('Invalid animation value at ' + formatPosition(value[2][0]) + '. Ignoring.');
+ }
+ }
+
+ return components;
+}
+
function background(property, compactable, validator) {
var image = _wrapDefault('background-image', property, compactable);
var position = _wrapDefault('background-position', property, compactable);
}
module.exports = {
+ animation: animation,
background: background,
border: widthStyleColor,
borderRadius: borderRadius,
var understandable = require('./properties/understandable');
+function animationIterationCount(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !(validator.isAnimationIterationCountKeyword(value2) || validator.isPositiveNumber(value2))) {
+ return false;
+ } else if (validator.isVariable(value1) && validator.isVariable(value2)) {
+ return true;
+ }
+
+ return validator.isAnimationIterationCountKeyword(value2) || validator.isPositiveNumber(value2);
+}
+
+function animationName(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !(validator.isAnimationNameKeyword(value2) || validator.isIdentifier(value2))) {
+ return false;
+ } else if (validator.isVariable(value1) && validator.isVariable(value2)) {
+ return true;
+ }
+
+ return validator.isAnimationNameKeyword(value2) || validator.isIdentifier(value2);
+}
+
+function animationTimingFunction(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !(validator.isAnimationTimingFunction(value2) || validator.isGlobal(value2))) {
+ return false;
+ } else if (validator.isVariable(value1) && validator.isVariable(value2)) {
+ return true;
+ }
+
+ return validator.isAnimationTimingFunction(value2) || validator.isGlobal(value2);
+}
+
function areSameFunction(validator, value1, value2) {
if (!validator.isFunction(value1) || !validator.isFunction(value2)) {
return false;
return validator.isUnit(value2) || validator.isColor(value2) || validator.isGlobal(value2);
}
+function time(validator, value1, value2) {
+ if (!understandable(validator, value1, value2, 0, true) && !validator.isTime(value2)) {
+ return false;
+ } else if (validator.isVariable(value1) && validator.isVariable(value2)) {
+ return true;
+ } else if (validator.isTime(value1) && !validator.isTime(value2)) {
+ return false;
+ } else if (validator.isTime(value2)) {
+ return true;
+ } else if (validator.isTime(value1)) {
+ return false;
+ } else if (validator.isFunction(value1) && !validator.isPrefixed(value1) && validator.isFunction(value2) && !validator.isPrefixed(value2)) {
+ return true;
+ }
+
+ return sameFunctionOrValue(validator, value1, value2);
+}
+
function unit(validator, value1, value2) {
if (!understandable(validator, value1, value2, 0, true) && !validator.isUnit(value2)) {
return false;
color: color,
components: components,
image: image,
+ time: time,
unit: unit
},
property: {
+ animationDirection: keywordWithGlobal('animation-direction'),
+ animationFillMode: keyword('animation-fill-mode'),
+ animationIterationCount: animationIterationCount,
+ animationName: animationName,
+ animationPlayState: keywordWithGlobal('animation-play-state'),
+ animationTimingFunction: animationTimingFunction,
backgroundAttachment: keyword('background-attachment'),
backgroundClip: keywordWithGlobal('background-clip'),
backgroundOrigin: keyword('background-origin'),
// Puts the shorthand together from its components.
//
var compactable = {
+ 'animation': {
+ canOverride: canOverride.generic.components([
+ canOverride.generic.time,
+ canOverride.property.animationTimingFunction,
+ canOverride.generic.time,
+ canOverride.property.animationIterationCount,
+ canOverride.property.animationDirection,
+ canOverride.property.animationFillMode,
+ canOverride.property.animationPlayState,
+ canOverride.property.animationName
+ ]),
+ components: [
+ 'animation-duration',
+ 'animation-timing-function',
+ 'animation-delay',
+ 'animation-iteration-count',
+ 'animation-direction',
+ 'animation-fill-mode',
+ 'animation-play-state',
+ 'animation-name'
+ ],
+ breakUp: breakUp.multiplex(breakUp.animation),
+ defaultValue: 'none',
+ restore: restore.multiplex(restore.withoutDefaults),
+ shorthand: true,
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-delay': {
+ canOverride: canOverride.generic.time,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: '0s',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-direction': {
+ canOverride: canOverride.property.animationDirection,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: 'normal',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-duration': {
+ canOverride: canOverride.generic.time,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: '0s',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-fill-mode': {
+ canOverride: canOverride.property.animationFillMode,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: 'none',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-iteration-count': {
+ canOverride: canOverride.property.animationIterationCount,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: '1',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-name': {
+ canOverride: canOverride.property.animationName,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: 'none',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-play-state': {
+ canOverride: canOverride.property.animationPlayState,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: 'running',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
+ 'animation-timing-function': {
+ canOverride: canOverride.property.animationTimingFunction,
+ componentOf: [
+ 'animation'
+ ],
+ defaultValue: 'ease',
+ intoMultiplexMode: 'real',
+ vendorPrefixes: [
+ '-moz-',
+ '-o-',
+ '-webkit-'
+ ]
+ },
'background': {
canOverride: canOverride.generic.components([
canOverride.generic.image,
var variableRegexStr = 'var\\(\\-\\-[^\\)]+\\)';
var functionAnyRegexStr = '(' + variableRegexStr + '|' + functionNoVendorRegexStr + '|' + functionVendorRegexStr + ')';
+var animationTimingFunctionRegex = /^(cubic\-bezier|steps)\([^\)]+\)$/;
var calcRegex = new RegExp('^(\\-moz\\-|\\-webkit\\-)?calc\\([^\\)]+\\)$', 'i');
var functionAnyRegex = new RegExp('^' + functionAnyRegexStr + '$', 'i');
var hslColorRegex = /^hsl\(\s*[\-\.\d]+\s*,\s*[\.\d]+%\s*,\s*[\.\d]+%\s*\)|hsla\(\s*[\-\.\d]+\s*,\s*[\.\d]+%\s*,\s*[\.\d]+%\s*,\s*[\.\d]+\s*\)$/;
+var identifierRegex = /^(\-[a-z0-9_][a-z0-9\-_]*|[a-z][a-z0-9\-_]*)$/i;
var longHexColorRegex = /^#[0-9a-f]{6}$/i;
var namedEntityRegex = /^[a-z]+$/i;
var prefixRegex = /^-([a-z0-9]|-)*$/i;
var rgbColorRegex = /^rgb\(\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*\)|rgba\(\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*,\s*[\d]{1,3}\s*,\s*[\.\d]+\s*\)$/;
var shortHexColorRegex = /^#[0-9a-f]{3}$/i;
+var timeRegex = new RegExp('^(\\-?\\+?\\.?\\d+\\.?\\d*(s|ms))$');
var urlRegex = /^url\([\s\S]+\)$/i;
var variableRegex = new RegExp('^' + variableRegexStr + '$', 'i');
'ridge',
'solid'
],
+ 'animation-direction': [
+ 'alternate',
+ 'alternate-reverse',
+ 'normal',
+ 'reverse'
+ ],
+ 'animation-fill-mode': [
+ 'backwards',
+ 'both',
+ 'forwards',
+ 'none'
+ ],
+ 'animation-iteration-count': [
+ 'infinite'
+ ],
+ 'animation-name': [
+ 'none'
+ ],
+ 'animation-play-state': [
+ 'paused',
+ 'running'
+ ],
+ 'animation-timing-function': [
+ 'ease',
+ 'ease-in',
+ 'ease-in-out',
+ 'ease-out',
+ 'linear',
+ 'step-end',
+ 'step-start'
+ ],
'background-attachment': [
'fixed',
'inherit',
'vw'
];
+function isAnimationTimingFunction() {
+ var isTimingFunctionKeyword = isKeyword('animation-timing-function');
+
+ return function (value) {
+ return isTimingFunctionKeyword(value) || animationTimingFunctionRegex.test(value);
+ };
+}
+
function isColor(value) {
return value != 'auto' &&
(
return hslColorRegex.test(value);
}
+function isIdentifier(value) {
+ return identifierRegex.test(value);
+}
+
function isImage(value) {
return value == 'none' || value == 'inherit' || isUrl(value);
}
return prefixRegex.test(value);
}
+function isPositiveNumber(value) {
+ return isNumber(value) &&
+ parseFloat(value) >= 0;
+}
+
function isVariable(value) {
return variableRegex.test(value);
}
+function isTime(value) {
+ return timeRegex.test(value);
+}
+
function isUnit(compatibleCssUnitRegex, value) {
return compatibleCssUnitRegex.test(value);
}
return {
colorOpacity: compatibility.colors.opacity,
+ isAnimationDirectionKeyword: isKeyword('animation-direction'),
+ isAnimationFillModeKeyword: isKeyword('animation-fill-mode'),
+ isAnimationIterationCountKeyword: isKeyword('animation-iteration-count'),
+ isAnimationNameKeyword: isKeyword('animation-name'),
+ isAnimationPlayStateKeyword: isKeyword('animation-play-state'),
+ isAnimationTimingFunction: isAnimationTimingFunction(),
isBackgroundAttachmentKeyword: isKeyword('background-attachment'),
isBackgroundClipKeyword: isKeyword('background-clip'),
isBackgroundOriginKeyword: isKeyword('background-origin'),
isGlobal: isKeyword('^'),
isHslColor: isHslColor,
isImage: isImage,
+ isIdentifier: isIdentifier,
isKeyword: isKeyword,
isLineHeightKeyword: isKeyword('line-height'),
isListStylePositionKeyword: isKeyword('list-style-position'),
isListStyleTypeKeyword: isKeyword('list-style-type'),
isPrefixed: isPrefixed,
+ isPositiveNumber: isPositiveNumber,
isRgbColor: isRgbColor,
isStyleKeyword: isKeyword('*-style'),
+ isTime: isTime,
isUnit: isUnit.bind(null, compatibleCssUnitRegex),
isUrl: isUrl,
isVariable: isVariable,
.progress{height:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}
.progress-bar{float:left;width:0;height:100%;line-height:20px;color:#fff;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}
.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}
-.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}
+.progress-bar.active,.progress.active .progress-bar{-webkit-animation:2s linear infinite progress-bar-stripes;-o-animation:2s linear infinite progress-bar-stripes;animation:2s linear infinite progress-bar-stripes}
.progress-bar-success{background-color:#5cb85c}
.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}
.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}
@media print{
.visible-print-inline-block{display:inline-block!important}
.hidden-print{display:none!important}
-}
+}
\ No newline at end of file
.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x,.btn.btn-large [class^=icon-].pull-left.icon-2x,.btn.btn-large [class^=icon-].pull-right.icon-2x{margin-top:.05em}
.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^=icon-].pull-left.icon-2x{margin-right:.2em}
.btn.btn-large [class*=" icon-"].pull-right.icon-2x,.btn.btn-large [class^=icon-].pull-right.icon-2x{margin-left:.2em}
-.icon-spin{-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}
+.icon-spin{-moz-animation:2s linear infinite spin;-o-animation:2s linear infinite spin;-webkit-animation:2s linear infinite spin;animation:2s linear infinite spin}
@-moz-keyframes spin{
0%{-moz-transform:rotate(0)}
100%{-moz-transform:rotate(359deg)}
vows.describe(breakUp)
.addBatch({
+ 'animation': {
+ 'all': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', '3s'],
+ ['property-value', 'ease-in'],
+ ['property-value', '1s'],
+ ['property-value', '2'],
+ ['property-value', 'reverse'],
+ ['property-value', 'both'],
+ ['property-value', 'paused'],
+ ['property-value', 'slidein']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-duration': function (components) {
+ assert.deepEqual(components[0].name, 'animation-duration');
+ assert.deepEqual(components[0].value, [['property-value', '3s']]);
+ },
+ 'has animation-timing-function': function (components) {
+ assert.deepEqual(components[1].name, 'animation-timing-function');
+ assert.deepEqual(components[1].value, [['property-value', 'ease-in']]);
+ },
+ 'has animation-delay': function (components) {
+ assert.deepEqual(components[2].name, 'animation-delay');
+ assert.deepEqual(components[2].value, [['property-value', '1s']]);
+ },
+ 'has animation-iteration-count': function (components) {
+ assert.deepEqual(components[3].name, 'animation-iteration-count');
+ assert.deepEqual(components[3].value, [['property-value', '2']]);
+ },
+ 'has animation-direction': function (components) {
+ assert.deepEqual(components[4].name, 'animation-direction');
+ assert.deepEqual(components[4].value, [['property-value', 'reverse']]);
+ },
+ 'has animation-fill-mode': function (components) {
+ assert.deepEqual(components[5].name, 'animation-fill-mode');
+ assert.deepEqual(components[5].value, [['property-value', 'both']]);
+ },
+ 'has animation-play-state': function (components) {
+ assert.deepEqual(components[6].name, 'animation-play-state');
+ assert.deepEqual(components[6].value, [['property-value', 'paused']]);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'slidein']]);
+ }
+ },
+ 'all with inverted order': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', 'slidein'],
+ ['property-value', 'paused'],
+ ['property-value', 'both'],
+ ['property-value', 'reverse'],
+ ['property-value', '2'],
+ ['property-value', '1s'],
+ ['property-value', 'ease-in'],
+ ['property-value', '3s']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-duration': function (components) {
+ assert.deepEqual(components[0].name, 'animation-duration');
+ assert.deepEqual(components[0].value, [['property-value', '1s']]);
+ },
+ 'has animation-timing-function': function (components) {
+ assert.deepEqual(components[1].name, 'animation-timing-function');
+ assert.deepEqual(components[1].value, [['property-value', 'ease-in']]);
+ },
+ 'has animation-delay': function (components) {
+ assert.deepEqual(components[2].name, 'animation-delay');
+ assert.deepEqual(components[2].value, [['property-value', '3s']]);
+ },
+ 'has animation-iteration-count': function (components) {
+ assert.deepEqual(components[3].name, 'animation-iteration-count');
+ assert.deepEqual(components[3].value, [['property-value', '2']]);
+ },
+ 'has animation-direction': function (components) {
+ assert.deepEqual(components[4].name, 'animation-direction');
+ assert.deepEqual(components[4].value, [['property-value', 'reverse']]);
+ },
+ 'has animation-fill-mode': function (components) {
+ assert.deepEqual(components[5].name, 'animation-fill-mode');
+ assert.deepEqual(components[5].value, [['property-value', 'both']]);
+ },
+ 'has animation-play-state': function (components) {
+ assert.deepEqual(components[6].name, 'animation-play-state');
+ assert.deepEqual(components[6].value, [['property-value', 'paused']]);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'slidein']]);
+ }
+ },
+ 'some': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', '3s'],
+ ['property-value', 'reverse'],
+ ['property-value', 'ease-in']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-duration': function (components) {
+ assert.deepEqual(components[0].name, 'animation-duration');
+ assert.deepEqual(components[0].value, [['property-value', '3s']]);
+ },
+ 'has animation-timing-function': function (components) {
+ assert.deepEqual(components[1].name, 'animation-timing-function');
+ assert.deepEqual(components[1].value, [['property-value', 'ease-in']]);
+ },
+ 'has animation-delay': function (components) {
+ assert.deepEqual(components[2].name, 'animation-delay');
+ assert.deepEqual(components[2].value, [['property-value', '0s']]);
+ },
+ 'has animation-iteration-count': function (components) {
+ assert.deepEqual(components[3].name, 'animation-iteration-count');
+ assert.deepEqual(components[3].value, [['property-value', '1']]);
+ },
+ 'has animation-direction': function (components) {
+ assert.deepEqual(components[4].name, 'animation-direction');
+ assert.deepEqual(components[4].value, [['property-value', 'reverse']]);
+ },
+ 'has animation-fill-mode': function (components) {
+ assert.deepEqual(components[5].name, 'animation-fill-mode');
+ assert.deepEqual(components[5].value, [['property-value', 'none']]);
+ },
+ 'has animation-play-state': function (components) {
+ assert.deepEqual(components[6].name, 'animation-play-state');
+ assert.deepEqual(components[6].value, [['property-value', 'running']]);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'none']]);
+ }
+ },
+ 'custom timing function': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', 'cubic-bezier(0.1, 0.7, 1.0, 0.1)']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-timing-function': function (components) {
+ assert.deepEqual(components[1].name, 'animation-timing-function');
+ assert.deepEqual(components[1].value, [['property-value', 'cubic-bezier(0.1, 0.7, 1.0, 0.1)']]);
+ }
+ },
+ 'invalid timing function': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', 'custom-bezier(0.1, 0.7, 1.0, 0.1)', [[1, 12, undefined]]]
+ ]
+ ]);
+ },
+ 'has no components': function (components) {
+ assert.lengthOf(components, 0);
+ }
+ },
+ 'custom animation name': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', 'custom-animation']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'custom-animation']]);
+ }
+ },
+ 'three time units': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', '1s'],
+ ['property-value', 'ease-in'],
+ ['property-value', '2s'],
+ ['property-value', '3s', [[1, 20, undefined]]]
+ ]
+ ]);
+ },
+ 'has no components': function (components) {
+ assert.lengthOf(components, 0);
+ }
+ },
+ 'repeated values': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', '1s'],
+ ['property-value', 'reverse'],
+ ['property-value', 'reverse']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'reverse']]);
+ }
+ },
+ 'inherit': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', 'inherit']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-duration': function (components) {
+ assert.deepEqual(components[0].name, 'animation-duration');
+ assert.deepEqual(components[0].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-timing-function': function (components) {
+ assert.deepEqual(components[1].name, 'animation-timing-function');
+ assert.deepEqual(components[1].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-delay': function (components) {
+ assert.deepEqual(components[2].name, 'animation-delay');
+ assert.deepEqual(components[2].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-iteration-count': function (components) {
+ assert.deepEqual(components[3].name, 'animation-iteration-count');
+ assert.deepEqual(components[3].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-direction': function (components) {
+ assert.deepEqual(components[4].name, 'animation-direction');
+ assert.deepEqual(components[4].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-fill-mode': function (components) {
+ assert.deepEqual(components[5].name, 'animation-fill-mode');
+ assert.deepEqual(components[5].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-play-state': function (components) {
+ assert.deepEqual(components[6].name, 'animation-play-state');
+ assert.deepEqual(components[6].value, [['property-value', 'inherit']]);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'inherit']]);
+ }
+ },
+ 'inherit mixed in': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', '1s', [[1, 12, undefined]]],
+ ['property-value', 'inherit']
+ ]
+ ]);
+ },
+ 'has no components': function (components) {
+ assert.lengthOf(components, 0);
+ }
+ },
+ 'multiplex': {
+ 'topic': function () {
+ return _breakUp([
+ [
+ 'property',
+ ['property-name', 'animation'],
+ ['property-value', '3s'],
+ ['property-value', 'ease-in'],
+ ['property-value', '1s'],
+ ['property-value', '2'],
+ ['property-value', 'reverse'],
+ ['property-value', 'both'],
+ ['property-value', 'paused'],
+ ['property-value', 'slidein'],
+ ['property-value', ','],
+ ['property-value', '2s'],
+ ['property-value', 'ease-out'],
+ ['property-value', 'slideout']
+ ]
+ ]);
+ },
+ 'has 8 components': function (components) {
+ assert.lengthOf(components, 8);
+ },
+ 'has animation-duration': function (components) {
+ assert.deepEqual(components[0].name, 'animation-duration');
+ assert.deepEqual(components[0].value, [['property-value', '3s'], ['property-value', ','], ['property-value', '2s']]);
+ },
+ 'has animation-timing-function': function (components) {
+ assert.deepEqual(components[1].name, 'animation-timing-function');
+ assert.deepEqual(components[1].value, [['property-value', 'ease-in'], ['property-value', ','], ['property-value', 'ease-out']]);
+ },
+ 'has animation-delay': function (components) {
+ assert.deepEqual(components[2].name, 'animation-delay');
+ assert.deepEqual(components[2].value, [['property-value', '1s'], ['property-value', ','], ['property-value', '0s']]);
+ },
+ 'has animation-iteration-count': function (components) {
+ assert.deepEqual(components[3].name, 'animation-iteration-count');
+ assert.deepEqual(components[3].value, [['property-value', '2'], ['property-value', ','], ['property-value', '1']]);
+ },
+ 'has animation-direction': function (components) {
+ assert.deepEqual(components[4].name, 'animation-direction');
+ assert.deepEqual(components[4].value, [['property-value', 'reverse'], ['property-value', ','], ['property-value', 'normal']]);
+ },
+ 'has animation-fill-mode': function (components) {
+ assert.deepEqual(components[5].name, 'animation-fill-mode');
+ assert.deepEqual(components[5].value, [['property-value', 'both'], ['property-value', ','], ['property-value', 'none']]);
+ },
+ 'has animation-play-state': function (components) {
+ assert.deepEqual(components[6].name, 'animation-play-state');
+ assert.deepEqual(components[6].value, [['property-value', 'paused'], ['property-value', ','], ['property-value', 'running']]);
+ },
+ 'has animation-name': function (components) {
+ assert.deepEqual(components[7].name, 'animation-name');
+ assert.deepEqual(components[7].value, [['property-value', 'slidein'], ['property-value', ','], ['property-value', 'slideout']]);
+ }
+ },
+ },
'background': {
'inherit': {
'topic': function () {
}
vows.describe(optimizeProperties)
+ .addBatch({
+ 'animation shorthand and longhand': {
+ 'topic': function () {
+ return _optimize('.block{animation:1s ease-in;animation-name:slidein}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 7, undefined]]],
+ ['property-value', '1s', [[1, 17, undefined]]],
+ ['property-value', 'ease-in', [[1, 20, undefined]]],
+ ['property-value', 'slidein', [[1, 43, undefined]]]
+ ]
+ ]);
+ }
+ },
+ 'animation longhand and shorthand': {
+ 'topic': function () {
+ return _optimize('.block{animation-fill-mode:both;animation:ease-in}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 32, undefined]]],
+ ['property-value', 'ease-in', [[1, 42, undefined]]],
+ ]
+ ]);
+ }
+ },
+ 'animation shorthand with overriddable shorthand': {
+ 'topic': function () {
+ return _optimize('.block{animation:1s infinite slidein;animation:ease-in 2}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 7, undefined]]],
+ ['property-value', 'ease-in', [[1, 47, undefined]]],
+ ['property-value', '2', [[1, 55, undefined]]]
+ ]
+ ]);
+ }
+ },
+ 'animation shorthand and multiplex longhand': {
+ 'topic': function () {
+ return _optimize('.block{animation:1s infinite slidein;animation-timing-function:ease-in,ease-out}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 7, undefined]]],
+ ['property-value', '1s', [[1, 17, undefined]]],
+ ['property-value', 'ease-in', [[1, 63, undefined]]],
+ ['property-value', 'infinite', [[1, 20, undefined]]],
+ ['property-value', 'slidein', [[1, 29, undefined]]],
+ ['property-value', ','],
+ ['property-value', '1s', [[1, 17, undefined]]],
+ ['property-value', 'ease-out', [[1, 71, undefined]]],
+ ['property-value', 'infinite', [[1, 20, undefined]]],
+ ['property-value', 'slidein', [[1, 29, undefined]]]
+ ]
+ ]);
+ }
+ },
+ 'animation multiplex shorthand and longhand': {
+ 'topic': function () {
+ return _optimize('.block{animation:ease-in,ease-out;animation-duration:1s}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 7, undefined]]],
+ ['property-value', '1s', [[1, 53, undefined]]],
+ ['property-value', 'ease-in', [[1, 17, undefined]]],
+ ['property-value', ','],
+ ['property-value', '1s', [[1, 53, undefined]]],
+ ['property-value', 'ease-out', [[1, 25, undefined]]]
+ ]
+ ]);
+ }
+ },
+ 'animation shorthand and multiplex longhand - too long to merge': {
+ 'topic': function () {
+ return _optimize('.block{animation:ease-in;animation-name:longname1,longname2,longname3}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 7, undefined]]],
+ ['property-value', 'ease-in', [[1, 17, undefined]]],
+ ],
+ [
+ 'property',
+ ['property-name', 'animation-name', [[1, 25, undefined]]],
+ ['property-value', 'longname1', [[1, 40, undefined]]],
+ ['property-value', ',', [[1, 49, undefined]]],
+ ['property-value', 'longname2', [[1, 50, undefined]]],
+ ['property-value', ',', [[1, 59, undefined]]],
+ ['property-value', 'longname3', [[1, 60, undefined]]]
+ ]
+ ]);
+ }
+ },
+ 'animation shorthand and inherit longhand': {
+ 'topic': function () {
+ return _optimize('.block{animation:1s infinite slidein;animation-timing-function:inherit}');
+ },
+ 'into': function (properties) {
+ assert.deepEqual(properties, [
+ [
+ 'property',
+ ['property-name', 'animation', [[1, 7, undefined]]],
+ ['property-value', '1s', [[1, 17, undefined]]],
+ ['property-value', 'infinite', [[1, 20, undefined]]],
+ ['property-value', 'slidein', [[1, 29, undefined]]]
+ ],
+ [
+ 'property',
+ ['property-name', 'animation-timing-function', [[1, 37, undefined]]],
+ ['property-value', 'inherit', [[1, 63, undefined]]]
+ ]
+ ]);
+ }
+ }
+ })
.addBatch({
'longhand then longhand - background colors as functions': {
'topic': function () {