Skip to content

Animations: extract keyframes from styles#9623

Merged
dvoytenko merged 4 commits intoampproject:masterfrom
dvoytenko:anim19
May 31, 2017
Merged

Animations: extract keyframes from styles#9623
dvoytenko merged 4 commits intoampproject:masterfrom
dvoytenko:anim19

Conversation

@dvoytenko
Copy link
Copy Markdown
Contributor

Partial for #9129.

@dvoytenko dvoytenko requested a review from aghassemi May 30, 2017 22:21
class CSSKeyframesRuleDef {
constructor() {
/** @type {string} */
this.name;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to set these values, declaring them like this doesn't help the JS engine's internal structure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just the definition for closure, in place of extern. Per closure it's fine. The class itself is not used - only its type.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you mark as an interface, then?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, but unfortunately can't. The underlying CSSRule is declared as a class, not interface. See this. This is kind of what our Def suffix means at this point. I'm going to contribute the same declarations to them, but we are slightly behind their externs version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, to remove this inconsistency, I just moved this declaration to our closure externs. So this should be now cleaner.

keyframeRule.keyText == 'from' ? 0 :
keyframeRule.keyText == 'to' ? 1 :
parseFloat(keyframeRule.keyText) / 100;
for (let j = 0; j < keyframeRule.style.length; j++) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: store style in a variable. Some engines do weird things (like re-initialize) when accessing native objects.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return null;
}
// Exlcude AMP's own styles.
if (styleNode.hasAttribute('amp-boilerplate') ||
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be if (!styleNode.hasAttribute('amp-custom'))?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (rule.name == name && isEnabled(win, rule)) {
return buildKeyframes(keyframesRule);
}
} else if (rule.type == /* CSSMediaRule */ 4) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checking media match before the recursion should be a decent optimization

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I didn't do this is because there are potentially a lot more @media definitions than @keyframes. And checking in each case is somewhat expensive. So instead I first find a likely candidate @keyframes name and then check if its parents are enabled recursively.

for (let j = 0; j < keyframeRule.style.length; j++) {
const styleName = keyframeRule.style[j];
let propName = styleName;
if (styleName == 'animation-timing-function') {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end with to account for vendor prefixes?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(TIL you could specify animation-timing-function in keyframe def, totally did not know this is possible)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Done.

const array = [];
for (let i = 0; i < keyframesRule.cssRules.length; i++) {
const keyframeRule = keyframesRule.cssRules[i];
const keyframe = {};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map()?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cssRules are of type CSSRuleList, so it's not an array :(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map returns an object?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @aghassemi meant map on all, e.g. const array = keyframesRule.cssRules.map(rule => {}). Unfortunately cssRules is not an array and I thought we decided to avoid simple toArray conversions just for better for-loops?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants