MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / third_party / polymer / components-chromium / core-animation / core-animation-extracted.js
blob7fe0497782c6349ad07f289f52d15d01450516ab
2 (function() {
4 function toNumber(value, allowInfinity) {
5 return (allowInfinity && value === 'Infinity') ? Number.POSITIVE_INFINITY : Number(value);
6 };
8 Polymer('core-animation',{
9 /**
10 * Fired when the animation completes.
12 * @event core-animation-finish
15 /**
17 * Fired when the web animation object changes.
19 * @event core-animation-change
22 publish: {
24 /**
25 * One or more nodes to animate.
27 * @property target
28 * @type HTMLElement|Node|Array<HTMLElement|Node>
30 target: {value: null, reflect: true},
32 /**
33 * Animation keyframes specified as an array of dictionaries of
34 * &lt;css properties&gt;:&lt;array of values&gt; pairs. For example,
36 * @property keyframes
37 * @type Object
39 keyframes: {value: null, reflect: true},
41 /**
42 * A custom animation function. Either provide this or `keyframes`. The signature
43 * of the callback is `EffectsCallback(timeFraction, target, animation)`
45 * @property customEffect
46 * @type Function(number, Object, Object)
48 customEffect: {value: null, reflect: true},
50 /**
51 * Controls the composition behavior. If set to "replace", the effect overrides
52 * the underlying value for the target. If set the "add", the effect is added to
53 * the underlying value for the target. If set to "accumulate", the effect is
54 * accumulated to the underlying value for the target.
56 * In cases such as numbers or lengths, "add" and "accumulate" produce the same
57 * value. In list values, "add" is appending to the list, while "accumulate" is
58 * adding the individual components of the list.
60 * For example, adding `translateX(10px)` and `translateX(25px)` produces
61 * `translateX(10px) translateX(25px)` and accumulating produces `translateX(35px)`.
63 * @property composite
64 * @type "replace"|"add"|"accumulate"
65 * @default "replace"
67 composite: {value: 'replace', reflect: true},
69 /**
70 * Animation duration in milliseconds, "Infinity", or "auto". "auto" is
71 * equivalent to 0.
73 * @property duration
74 * @type number|"Infinity"
75 * @default "auto"
77 duration: {value: 'auto', reflect: true},
79 /**
80 * Controls the effect the animation has on the target when it's not playing.
81 * The possible values are "none", "forwards", "backwards", "both" or "auto".
83 * "none" means the animation has no effect when it's not playing.
85 * "forward" applies the value at the end of the animation after it's finished.
87 * "backwards" applies the value at the start of the animation to the target
88 * before it starts playing and has no effect when the animation finishes.
90 * "both" means "forwards" and "backwards". "auto" is equivalent to "none".
92 * @property fill
93 * @type "none"|"forwards"|"backwards"|"both"|"auto"
94 * @default "auto"
96 fill: {value: 'auto', reflect: true},
98 /**
99 * A transition timing function. The values are equivalent to the CSS
100 * counterparts.
102 * @property easing
103 * @type string
104 * @default "linear"
106 easing: {value: 'linear', reflect: true},
109 * The number of milliseconds to delay before beginning the animation.
111 * @property delay
112 * @type Number
113 * @default 0
115 delay: {value: 0, reflect: true},
118 * The number of milliseconds to wait after the animation finishes. This is
119 * useful, for example, in an animation group to wait for some time before
120 * beginning the next item in the animation group.
122 * @property endDelay
123 * @type number
124 * @default 0
126 endDelay: {value: 0, reflect: true},
129 * The number of iterations this animation should run for.
131 * @property iterations
132 * @type Number|'Infinity'
133 * @default 1
135 iterations: {value: 1, reflect: true},
138 * Number of iterations into the animation in which to begin the effect.
139 * For example, setting this property to 0.5 and `iterations` to 2 will
140 * cause the animation to begin halfway through the first iteration but still
141 * run twice.
143 * @property iterationStart
144 * @type Number
145 * @default 0
147 iterationStart: {value: 0, reflect: true},
150 * (not working in web animations polyfill---do not use)
152 * Controls the iteration composition behavior. If set to "replace", the effect for
153 * every iteration is independent of each other. If set to "accumulate", the effect
154 * for iterations of the animation will build upon the value in the previous iteration.
156 * Example:
158 * // Moves the target 50px on the x-axis over 5 iterations.
159 * <core-animation iterations="5" iterationComposite="accumulate">
160 * <core-animation-keyframe>
161 * <core-animation-prop name="transform" value="translateX(10px)"></core-animation-prop>
162 * </core-animation-keyframe>
163 * </core-animation>
165 * @property iterationComposite
166 * @type "replace"|"accumulate"
167 * @default false
169 iterationComposite: {value: 'replace', reflect: true},
172 * The playback direction of the animation. "normal" plays the animation in the
173 * normal direction. "reverse" plays it in the reverse direction. "alternate"
174 * alternates the playback direction every iteration such that even iterations are
175 * played normally and odd iterations are reversed. "alternate-reverse" plays
176 * even iterations in the reverse direction and odd iterations in the normal
177 * direction.
179 * @property direction
180 * @type "normal"|"reverse"|"alternate"|"alternate-reverse"
181 * @default "normal"
183 direction: {value: 'normal', reflect: true},
186 * A multiplier to the playback rate to the animation.
188 * @property playbackRate
189 * @type number
190 * @default 1
192 playbackRate: {value: 1, reflect: true},
195 * If set to true, play the animation when it is created or a property is updated.
197 * @property autoplay
198 * @type boolean
199 * @default false
201 autoplay: {value: false, reflect: true}
205 animation: false,
207 observe: {
208 target: 'apply',
209 keyframes: 'apply',
210 customEffect: 'apply',
211 composite: 'apply',
212 duration: 'apply',
213 fill: 'apply',
214 easing: 'apply',
215 iterations: 'apply',
216 iterationStart: 'apply',
217 iterationComposite: 'apply',
218 delay: 'apply',
219 endDelay: 'apply',
220 direction: 'apply',
221 playbackRate: 'apply',
222 autoplay: 'apply'
225 ready: function() {
226 this.apply();
230 * Plays the animation. If the animation is currently paused, seeks the animation
231 * to the beginning before starting playback.
233 * @method play
234 * @return AnimationPlayer The animation player.
236 play: function() {
237 this.apply();
238 if (this.animation && !this.autoplay) {
239 this.player = document.timeline.play(this.animation);
240 this.player.onfinish = this.animationFinishHandler.bind(this);
241 return this.player;
246 * Stops the animation and clears all effects on the target.
248 * @method cancel
250 cancel: function() {
251 if (this.player) {
252 this.player.cancel();
257 * Seeks the animation to the end.
259 * @method finish
261 finish: function() {
262 if (this.player) {
263 this.player.finish();
268 * Pauses the animation.
270 * @method pause
272 pause: function() {
273 if (this.player) {
274 this.player.pause();
279 * @method hasTarget
280 * @return boolean True if `target` is defined.
282 hasTarget: function() {
283 return this.target !== null;
287 * Creates a web animations object based on this object's properties, and
288 * plays it if autoplay is true.
290 * @method apply
291 * @return Object A web animation.
293 apply: function() {
294 this.animation = this.makeAnimation();
295 if (this.autoplay && this.animation) {
296 this.play();
298 return this.animation;
301 makeSingleAnimation: function(target) {
302 // XXX(yvonne): for selecting all the animated elements.
303 target.classList.add('core-animation-target');
304 return new Animation(target, this.animationEffect, this.timingProps);
307 makeAnimation: function() {
308 if (!this.target) {
309 return null;
311 var animation;
312 if (Array.isArray(this.target)) {
313 var array = [];
314 this.target.forEach(function(t) {
315 array.push(this.makeSingleAnimation(t));
316 }.bind(this));
317 animation = new AnimationGroup(array);
318 } else {
319 animation = this.makeSingleAnimation(this.target);
321 return animation;
324 animationChanged: function() {
325 // Sending 'this' with the event so you can always get the animation object
326 // that fired the event, due to event retargetting in shadow DOM.
327 this.fire('core-animation-change', this);
330 targetChanged: function(old) {
331 if (old) {
332 old.classList.remove('core-animation-target');
336 get timingProps() {
337 var props = {};
338 var timing = {
339 delay: {isNumber: true},
340 endDelay: {isNumber: true},
341 fill: {},
342 iterationStart: {isNumber: true},
343 iterations: {isNumber: true, allowInfinity: true},
344 duration: {isNumber: true},
345 playbackRate: {isNumber: true},
346 direction: {},
347 easing: {}
349 for (t in timing) {
350 if (this[t] !== null) {
351 var name = timing[t].property || t;
352 props[name] = timing[t].isNumber && this[t] !== 'auto' ?
353 toNumber(this[t], timing[t].allowInfinity) : this[t];
356 return props;
359 get animationEffect() {
360 var props = {};
361 var frames = [];
362 var effect;
363 if (this.keyframes) {
364 frames = this.keyframes;
365 } else if (!this.customEffect) {
366 var children = this.querySelectorAll('core-animation-keyframe');
367 if (children.length === 0) {
368 children = this.shadowRoot.querySelectorAll('core-animation-keyframe');
370 Array.prototype.forEach.call(children, function(c) {
371 frames.push(c.properties);
374 if (this.customEffect) {
375 effect = this.customEffect;
376 } else {
377 effect = new KeyframeEffect(frames, this.composite);
379 return effect;
382 animationFinishHandler: function() {
383 this.fire('core-animation-finish');
387 })();
390 Polymer('core-animation-keyframe',{
391 publish: {
393 * An offset from 0 to 1.
395 * @property offset
396 * @type Number
398 offset: {value: null, reflect: true}
400 get properties() {
401 var props = {};
402 var children = this.querySelectorAll('core-animation-prop');
403 Array.prototype.forEach.call(children, function(c) {
404 props[c.name] = c.value;
406 if (this.offset !== null) {
407 props.offset = this.offset;
409 return props;
414 Polymer('core-animation-prop',{
415 publish: {
417 * A CSS property name.
419 * @property name
420 * @type string
422 name: {value: '', reflect: true},
425 * The value for the CSS property.
427 * @property value
428 * @type string|number
430 value: {value: '', reflect: true}