-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Non-destructive @keyframes
rule transformation.
#3163
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,11 +25,15 @@ | |
// decorates styles with rule info and returns an array of used style | ||
// property names | ||
decorateStyles: function(styles) { | ||
var self = this, props = {}; | ||
var self = this, props = {}, keyframes = []; | ||
styleUtil.forRulesInStyles(styles, function(rule) { | ||
self.decorateRule(rule); | ||
self.collectPropertiesInCssText(rule.propertyInfo.cssText, props); | ||
}, function onKeyframesRule(rule) { | ||
keyframes.push(rule); | ||
}); | ||
// Cache all found keyframes rules for later reference: | ||
styles._keyframes = keyframes; | ||
// return this list of property names *consumes* in these styles. | ||
var names = []; | ||
for (var i in props) { | ||
|
@@ -87,7 +91,10 @@ | |
var parts = cssText.split(';'); | ||
for (var i=0, p; i<parts.length; i++) { | ||
p = parts[i]; | ||
if (p.match(this.rx.MIXIN_MATCH) || p.match(this.rx.VAR_MATCH)) { | ||
if (p.match(this.rx.MIXIN_MATCH) || | ||
p.match(this.rx.VAR_MATCH) || | ||
this.rx.ANIMATION_MATCH.test(p) || | ||
styleUtil.isKeyframesSelector(rule)) { | ||
customCssText += p + ';\n'; | ||
} | ||
} | ||
|
@@ -181,6 +188,46 @@ | |
rule.cssText = output; | ||
}, | ||
|
||
// Apply keyframe transformations to the cssText of a given rule. The | ||
// keyframeTransforms object is a map of keyframe names to transformer | ||
// functions which take in cssText and spit out transformed cssText. | ||
applyKeyframeTransforms: function(rule, keyframeTransforms) { | ||
var input = rule.cssText; | ||
var output = rule.cssText; | ||
if (rule.hasAnimations == null) { | ||
// Cache whether or not the rule has any animations to begin with: | ||
rule.hasAnimations = this.rx.ANIMATION_MATCH.test(input); | ||
} | ||
// If there are no animations referenced, we can skip transforms: | ||
if (rule.hasAnimations) { | ||
var transform; | ||
// If we haven't transformed this rule before, we iterate over all | ||
// transforms: | ||
if (rule.keyframeNamesToTransform == null) { | ||
rule.keyframeNamesToTransform = []; | ||
for (var keyframe in keyframeTransforms) { | ||
transform = keyframeTransforms[keyframe]; | ||
output = transform(input); | ||
// If the transform actually changed the CSS text, we cache the | ||
// transform name for future use: | ||
if (input !== output) { | ||
input = output; | ||
rule.keyframeNamesToTransform.push(keyframe); | ||
} | ||
} | ||
} else { | ||
// If we already have a list of keyframe names that apply to this | ||
// rule, we apply only those keyframe name transforms: | ||
for (var i = 0; i < rule.keyframeNamesToTransform.length; ++i) { | ||
transform = keyframeTransforms[rule.keyframeNamesToTransform[i]]; | ||
input = transform(input); | ||
} | ||
output = input; | ||
} | ||
} | ||
rule.cssText = output; | ||
}, | ||
|
||
// Test if the rules in these styles matches the given `element` and if so, | ||
// collect any custom properties into `props`. | ||
propertyDataFromStyles: function(styles, element) { | ||
|
@@ -256,15 +303,60 @@ | |
hostSelector; | ||
var hostRx = new RegExp(this.rx.HOST_PREFIX + rxHostSelector + | ||
this.rx.HOST_SUFFIX); | ||
var keyframeTransforms = | ||
this._elementKeyframeTransforms(element, scopeSelector); | ||
return styleTransformer.elementStyles(element, function(rule) { | ||
self.applyProperties(rule, properties); | ||
if (rule.cssText && !nativeShadow) { | ||
if (!nativeShadow && | ||
!Polymer.StyleUtil.isKeyframesSelector(rule) && | ||
rule.cssText) { | ||
// NOTE: keyframe transforms only scope munge animation names, so it | ||
// is not necessary to apply them in ShadowDOM. | ||
self.applyKeyframeTransforms(rule, keyframeTransforms); | ||
self._scopeSelector(rule, hostRx, hostSelector, | ||
element._scopeCssViaAttr, scopeSelector); | ||
} | ||
}); | ||
}, | ||
|
||
_elementKeyframeTransforms: function(element, scopeSelector) { | ||
var keyframesRules = element._styles._keyframes; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like this keyframes specific handling should be factored into a separate function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will fix. |
||
var keyframeTransforms = {}; | ||
if (!nativeShadow) { | ||
// For non-ShadowDOM, we transform all known keyframes rules in | ||
// advance for the current scope. This allows us to catch keyframes | ||
// rules that appear anywhere in the stylesheet: | ||
for (var i = 0, keyframesRule = keyframesRules[i]; | ||
i < keyframesRules.length; | ||
keyframesRule = keyframesRules[++i]) { | ||
this._scopeKeyframes(keyframesRule, scopeSelector); | ||
keyframeTransforms[keyframesRule.keyframesName] = | ||
this._keyframesRuleTransformer(keyframesRule); | ||
} | ||
} | ||
return keyframeTransforms; | ||
}, | ||
|
||
// Generate a factory for transforming a chunk of CSS text to handle a | ||
// particular scoped keyframes rule. | ||
_keyframesRuleTransformer: function(keyframesRule) { | ||
return function(cssText) { | ||
return cssText.replace( | ||
keyframesRule.keyframesNameRx, | ||
keyframesRule.transformedKeyframesName); | ||
}; | ||
}, | ||
|
||
// Transforms `@keyframes` names to be unique for the current host. | ||
// Example: @keyframes foo-anim -> @keyframes foo-anim-x-foo-0 | ||
_scopeKeyframes: function(rule, scopeId) { | ||
rule.keyframesNameRx = new RegExp(rule.keyframesName, 'g'); | ||
rule.transformedKeyframesName = rule.keyframesName + '-' + scopeId; | ||
rule.transformedSelector = rule.transformedSelector || rule.selector; | ||
rule.selector = rule.transformedSelector.replace( | ||
rule.keyframesName, rule.transformedKeyframesName); | ||
}, | ||
|
||
// Strategy: x scope shim a selector e.g. to scope `.x-foo-42` (via classes): | ||
// non-host selector: .a.x-foo -> .x-foo-42 .a.x-foo | ||
// host selector: x-foo.wide -> x-foo.x-foo-42.wide | ||
|
@@ -359,6 +451,7 @@ | |
// var(--a, fallback-literal(with-one-nested-parentheses)) | ||
VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,)]*)|(?:[^;]*\([^;)]*\)))[\s]*?\)/gi, | ||
VAR_CAPTURE: /\([\s]*(--[^,\s)]*)(?:,[\s]*(--[^,\s)]*))?(?:\)|,)/gi, | ||
ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/, | ||
IS_VAR: /^--/, | ||
BRACKETED: /\{[^}]*\}/g, | ||
HOST_PREFIX: '(?:^|[^.#[:])', | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<!doctype html> | ||
<!-- | ||
@license | ||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | ||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt | ||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | ||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt | ||
Code distributed by Google as part of the polymer project is also | ||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt | ||
--> | ||
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script> | ||
<link rel="import" href="../../polymer.html"> | ||
|
||
<body> | ||
<style is="custom-style"> | ||
:root { | ||
--color: blue; | ||
--anim-color: red; | ||
} | ||
|
||
.alternative { | ||
--color: green; | ||
--anim-color: blue; | ||
} | ||
</style> | ||
|
||
<dom-module id="test-keyframes"> | ||
<template><style> | ||
:host { | ||
display: block; | ||
color: var(--color); | ||
animation: foo 3s; | ||
height: 20px; | ||
} | ||
|
||
@keyframes foo { | ||
0% { | ||
background: var(--anim-color); | ||
} | ||
|
||
100% { | ||
background: yellow; | ||
} | ||
} | ||
</style><content></content></template> | ||
<script> | ||
Polymer({ | ||
is: 'test-keyframes' | ||
}); | ||
|
||
</script> | ||
</dom-module> | ||
|
||
<p>Text should be the color blue. Background should animate from the color red to the color yellow, and then become transparent.</p> | ||
<test-keyframes>red</test-keyframes> | ||
|
||
<p>Text should be the color green. Background should animate from the color blue to the color yellow, and then become transparent.</p> | ||
<test-keyframes class="alternative">blue</test-keyframes> | ||
|
||
</body> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a reminder to hopefully lessen confusion in the future.