├── .gitignore ├── .gitmodules ├── .travis-setup.sh ├── .travis.yml ├── CONTRIBUTING.md ├── COPYING ├── Gruntfile.js ├── History.md ├── README.md ├── bower.json ├── docs ├── examples.md ├── experimental.md └── support.md ├── externs ├── README.md ├── web-animations-next.js └── web-animations.js ├── node_modules ├── chai │ └── chai.js └── mocha │ ├── LICENSE │ ├── mocha.css │ └── mocha.js ├── package-lock.json ├── package.json ├── src ├── animation.js ├── apply-preserving-inline-style.js ├── apply.js ├── box-handler.js ├── color-handler.js ├── deprecation.js ├── dev.js ├── dimension-handler.js ├── effect-callback.js ├── element-animatable.js ├── font-weight-handler.js ├── group-constructors.js ├── handler-utils.js ├── interpolation.js ├── keyframe-effect-constructor.js ├── keyframe-effect.js ├── keyframe-interpolations.js ├── matrix-decomposition.js ├── matrix-interpolation.js ├── normalize-keyframes.js ├── number-handler.js ├── position-handler.js ├── property-interpolation.js ├── property-names.js ├── scope.js ├── shadow-handler.js ├── shape-handler.js ├── tick.js ├── timeline.js ├── timing-utilities.js ├── transform-handler.js ├── visibility-handler.js ├── web-animations-bonus-cancel-events.js ├── web-animations-bonus-object-form-keyframes.js └── web-animations-next-animation.js ├── target-config.js ├── target-loader.js ├── templates ├── boilerplate ├── runner.html ├── web-animations.html └── web-animations.js ├── test ├── blink │ ├── 2-keyframes-with-offsets.html │ ├── 3-keyframes-with-offsets.html │ ├── add-keyframes.html │ ├── eased-keyframes.html │ ├── get-animations.html │ ├── get-css-animations.html │ ├── insufficient-keyframes.html │ ├── interpolation │ │ ├── background-color-interpolation.html │ │ ├── background-image-interpolation.html │ │ ├── background-position-interpolation.html │ │ ├── background-position-origin-interpolation.html │ │ ├── background-size-interpolation.html │ │ ├── border-color-interpolation.html │ │ ├── border-image-outset-interpolation.html │ │ ├── border-image-slice-interpolation.html │ │ ├── border-image-source-interpolation.html │ │ ├── border-image-width-interpolation.html │ │ ├── border-radius-interpolation.html │ │ ├── border-spacing-interpolation.html │ │ ├── border-width-interpolation.html │ │ ├── bottom-interpolation.html │ │ ├── box-shadow-interpolation.html │ │ ├── calc-interpolation.html │ │ ├── clip-interpolation.html │ │ ├── color-interpolation.html │ │ ├── filter-interpolation.html │ │ ├── flex-interpolation.html │ │ ├── font-size-interpolation.html │ │ ├── font-weight-interpolation.html │ │ ├── height-interpolation.html │ │ ├── left-interpolation.html │ │ ├── letter-spacing-interpolation.html │ │ ├── line-height-interpolation.html │ │ ├── list-style-image-interpolation.html │ │ ├── margin-interpolation.html │ │ ├── max-height-interpolation.html │ │ ├── max-width-interpolation.html │ │ ├── min-height-interpolation.html │ │ ├── min-width-interpolation.html │ │ ├── object-position-interpolation.html │ │ ├── opacity-interpolation.html │ │ ├── orphans-interpolation.html │ │ ├── outline-color-interpolation.html │ │ ├── outline-offset-interpolation.html │ │ ├── outline-width-interpolation.html │ │ ├── padding-interpolation.html │ │ ├── perspective-interpolation.html │ │ ├── perspective-origin-interpolation.html │ │ ├── resources │ │ │ └── interpolation-test.js │ │ ├── right-interpolation.html │ │ ├── shape-image-threshold.html │ │ ├── shape-margin.html │ │ ├── shape-outside.html │ │ ├── text-decoration-color-interpolation.html │ │ ├── text-indent-interpolation.html │ │ ├── text-shadow-interpolation.html │ │ ├── top-interpolation.html │ │ ├── transform-matrix-interpolation.html │ │ ├── transform-none-interpolation.html │ │ ├── transform-origin-interpolation.html │ │ ├── transform-perspective-interpolation.html │ │ ├── transform-rotate-interpolation.html │ │ ├── transform-scale-interpolation.html │ │ ├── transform-skew-interpolation.html │ │ ├── transform-translate-interpolation.html │ │ ├── vertical-align-interpolation.html │ │ ├── viewport-unit-interpolation.html │ │ ├── visibility-interpolation.html │ │ ├── widows-interpolation.html │ │ ├── width-interpolation.html │ │ ├── word-spacing-interpolation.html │ │ └── z-index-interpolation.html │ ├── keyframe-properties.html │ ├── keyframes-with-null-offsets.html │ ├── out-of-order-keyframes.html │ ├── resources │ │ ├── blue-100.png │ │ ├── green-100.png │ │ ├── green-20.png │ │ ├── keyframes-test.js │ │ ├── stripes-100.png │ │ └── stripes-20.png │ ├── same-offset-keyframes.html │ └── simple-keyframes.html ├── js │ ├── animation-cancel-event.js │ ├── animation-finish-event.js │ ├── animation.js │ ├── apply-preserving-inline-style.js │ ├── box-handler.js │ ├── color-handler.js │ ├── dimension-handler.js │ ├── effect-callback.js │ ├── group-animation-cancel-event.js │ ├── group-animation-finish-event.js │ ├── group-animation.js │ ├── group-constructors.js │ ├── interpolation.js │ ├── keyframe-effect-constructor.js │ ├── keyframes.js │ ├── matrix-interpolation.js │ ├── number-handler.js │ ├── property-interpolation.js │ ├── tick.js │ ├── timeline.js │ ├── timing-utilities.js │ ├── timing.js │ ├── transform-handler.js │ ├── visibility-handler.js │ └── web-animations-next-animation.js ├── karma-config-ci.js ├── karma-config.js ├── karma-mocha-setup.js ├── karma-testharness-adapter.js ├── resources │ └── testharnessreport.js ├── runner-web-animations-next-lite.html ├── runner-web-animations-next.html ├── runner-web-animations.html ├── runner.js ├── testharness-runner.html ├── testharness-runner.js ├── testharness-tests.js └── web-platform-tests-expectations.js ├── web-animations-next-lite.dev.html ├── web-animations-next-lite.dev.js ├── web-animations-next-lite.min.html ├── web-animations-next.dev.html ├── web-animations-next.dev.js ├── web-animations-next.min.html ├── web-animations.dev.html ├── web-animations.dev.js ├── web-animations.html └── web-animations.min.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | !node_modules/mocha/mocha.css 3 | !node_modules/mocha/mocha.js 4 | !node_modules/mocha/LICENCE 5 | !node_modules/chai/chai.js 6 | !node_modules/chai-LICENCE 7 | 8 | inter-* 9 | *.min.js* 10 | 11 | *~ 12 | sauce_connect.log 13 | test.html 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/web-platform-tests"] 2 | path = test/web-platform-tests 3 | url = https://github.com/web-platform-tests/wpt.git 4 | -------------------------------------------------------------------------------- /.travis-setup.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2014 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #! /bin/bash 16 | 17 | set -x 18 | set -e 19 | 20 | # Make sure /dev/shm has correct permissions. 21 | ls -l /dev/shm 22 | sudo chmod 1777 /dev/shm 23 | ls -l /dev/shm 24 | 25 | uname -a 26 | cat /etc/lsb-release 27 | 28 | npm install 29 | # npm may update the package-lock.json. Revert this to avoid failing grunt-checkrepo. 30 | git checkout HEAD package-lock.json 31 | 32 | npm install -g grunt-cli 33 | 34 | sudo apt-get update --fix-missing 35 | 36 | # Install python-imaging from the environment rather then build it. 37 | # If the below fails, pip will build it via the requirements.txt 38 | # sudo apt-get install python-imaging 39 | # VIRTUAL_ENV_site_packages=$(echo $VIRTUAL_ENV/lib/*/site-packages) 40 | # VIRTUAL_ENV_python_version=$(echo $VIRTUAL_ENV_site_packages | sed -e's@.*/\(.*\)/site-packages@\1@') 41 | # ln -s /usr/lib/$VIRTUAL_ENV_python_version/dist-packages/PIL.pth $VIRTUAL_ENV_site_packages/PIL.pth 42 | # ln -s /usr/lib/$VIRTUAL_ENV_python_version/dist-packages/PIL $VIRTUAL_ENV_site_packages/PIL 43 | 44 | export VERSION=$(echo $BROWSER | sed -e's/[^-]*-//') 45 | export BROWSER=$(echo $BROWSER | sed -e's/-.*//') 46 | 47 | echo BROWSER=$BROWSER 48 | echo VERSION=$VERSION 49 | 50 | sudo ln -sf $(which true) $(which xdg-desktop-menu) 51 | 52 | case $BROWSER in 53 | Android) 54 | sudo apt-get install -qq --force-yes \ 55 | libc6:i386 libgcc1:i386 gcc-4.6-base:i386 libstdc++5:i386 \ 56 | libstdc++6:i386 lib32z1 libreadline6-dev:i386 \ 57 | libncurses5-dev:i386 58 | bash tools/android/setup.sh 59 | ;; 60 | 61 | Chrome) 62 | echo "Getting $VERSION of $BROWSER" 63 | export CHROME=google-chrome-${VERSION}_current_amd64.deb 64 | wget https://dl.google.com/linux/direct/$CHROME 65 | sudo dpkg --install $CHROME || sudo apt-get -f install 66 | which google-chrome 67 | ls -l `which google-chrome` 68 | 69 | if [ -f /opt/google/chrome/chrome-sandbox ]; then 70 | export CHROME_SANDBOX=/opt/google/chrome/chrome-sandbox 71 | else 72 | export CHROME_SANDBOX=$(ls /opt/google/chrome*/chrome-sandbox) 73 | fi 74 | 75 | # Download a custom chrome-sandbox which works inside OpenVC containers (used on travis). 76 | sudo rm -f $CHROME_SANDBOX 77 | sudo wget https://googledrive.com/host/0B5VlNZ_Rvdw6NTJoZDBSVy1ZdkE -O $CHROME_SANDBOX 78 | sudo chown root:root $CHROME_SANDBOX; sudo chmod 4755 $CHROME_SANDBOX 79 | sudo md5sum $CHROME_SANDBOX 80 | 81 | google-chrome --version 82 | ;; 83 | 84 | Firefox) 85 | sudo rm -f /usr/local/bin/firefox 86 | case $VERSION in 87 | stable) 88 | ;; 89 | beta) 90 | yes "\n" | sudo add-apt-repository -y ppa:mozillateam/firefox-next 91 | ;; 92 | # TODO(alancutter): Add support for firefox-aurora. 93 | # This will need to download the binary manually as the ubuntu-mozilla-daily 94 | # ppa doesn't support the version of linux that Travis uses. 95 | esac 96 | sudo apt-get update --fix-missing 97 | sudo apt-get install firefox 98 | which firefox 99 | ls -l `which firefox` 100 | firefox --version 101 | ;; 102 | esac 103 | 104 | # R=tools/python/requirements.txt 105 | # pip install -r $R --use-mirrors || pip install -r $R 106 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | services: xvfb 3 | language: node_js 4 | node_js: "10.15.3" 5 | install: BROWSER="Firefox-stable" ./.travis-setup.sh 6 | script: xvfb-run -a npm test 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | What is Web Animations? 3 | ----------------------- 4 | 5 | A new JavaScript API for driving animated content on the web. By unifying 6 | the animation features of SVG and CSS, Web Animations unlocks features 7 | previously only usable declaratively, and exposes powerful, high-performance 8 | animation capabilities to developers. 9 | 10 | What is in this repository? 11 | --------------------------- 12 | 13 | A JavaScript implementation of the Web Animations API that provides Web 14 | Animation features in browsers that do not support it natively. The polyfill 15 | falls back to the native implementation when one is available. 16 | 17 | Quick start 18 | ----------- 19 | 20 | Here's a simple example of an animation that fades and scales a `
`. 21 | [Try it as a live demo.](http://jsbin.com/yageyezabo/edit?html,js,output) 22 | 23 | ```html 24 | 25 | 26 | 27 | 28 |
Hello world!
29 | 30 | 31 | 42 | ``` 43 | 44 | Documentation 45 | ------------- 46 | 47 | * [Codelab tutorial](https://github.com/web-animations/web-animations-codelabs) 48 | * [Examples of usage](/docs/examples.md) 49 | * [Live demos](https://web-animations.github.io/web-animations-demos) 50 | * [MDN reference](https://developer.mozilla.org/en-US/docs/Web/API/Element/animate) 51 | * [W3C specification](https://drafts.csswg.org/web-animations/) 52 | 53 | We love feedback! 54 | ----------------- 55 | 56 | * For feedback on the API and the specification: 57 | * File an issue on GitHub: 58 | * Alternatively, send an email to with subject line 59 | "[web-animations] ... message topic ..." 60 | ([archives](http://lists.w3.org/Archives/Public/public-fx/)). 61 | 62 | * For issues with the polyfill, report them on GitHub: 63 | . 64 | 65 | Keep up-to-date 66 | --------------- 67 | 68 | Breaking polyfill changes will be announced on this low-volume mailing list: 69 | [web-animations-changes@googlegroups.com](https://groups.google.com/forum/#!forum/web-animations-changes). 70 | 71 | More info 72 | --------- 73 | 74 | * [Technical details about the polyfill](/docs/support.md) 75 | * [Browser support](/docs/support.md#browser-support) 76 | * [Fallback to native](/docs/support.md#native-fallback) 77 | * [Feature list](/docs/support.md#features) 78 | * [Feature deprecation and removal processes](/docs/support.md#process-for-breaking-changes) 79 | * To test experimental API features, try one of the 80 | [experimental targets](/docs/experimental.md) 81 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-animations-js", 3 | "description": "JavaScript implementation of the Web Animations API", 4 | "homepage": "https://github.com/web-animations/web-animations-js", 5 | "main": "web-animations.min.js", 6 | "moduleType": [ 7 | "globals" 8 | ], 9 | "keywords": [ 10 | "animations", 11 | "polyfill" 12 | ], 13 | "license": "Apache-2.0", 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "templates", 18 | "test", 19 | "Gruntfile.js", 20 | "package.json", 21 | "target-config.js", 22 | "target-loader.js", 23 | "web-animations.dev.html", 24 | "web-animations.dev.js", 25 | "web-animations-next.dev.html", 26 | "web-animations-next.dev.js", 27 | "web-animations-next-lite.dev.html", 28 | "web-animations-next-lite.dev.js" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /docs/experimental.md: -------------------------------------------------------------------------------- 1 | 2 | Experimental build targets 3 | -------------------------- 4 | 5 | Most people should use the basic polyfill in `web-animations.min.js`. This 6 | tracks the Web Animations features that are supported natively in browsers. 7 | However, we also provide two additional build targets that contain experimental 8 | features. 9 | 10 | ### web-animations-next.min.js 11 | 12 | Contains all of web-animations.min.js plus features that are still undergoing 13 | discussion or have yet to be implemented natively. 14 | 15 | ### web-animations-next-lite.min.js 16 | 17 | A cut down version of web-animations-next, it removes several lesser used 18 | property handlers and some of the larger and less used features such as matrix 19 | interpolation/decomposition. 20 | 21 | Build target comparison 22 | ----------------------- 23 | 24 | | | web-animations | web-animations-next | web-animations-next-lite | 25 | |------------------------|:--------------:|:-------------------:|:------------------------:| 26 | |Size (gzipped) | 15KB | 19KB | 15KB | 27 | |Element.animate | ✔ | ✔ | ✔ | 28 | |Timing input (easings, duration, fillMode, etc.) for animation effects| ✔ | ✔ | ✔ | 29 | |Playback control | ✔ | ✔ | ✔ | 30 | |Support for animating lengths, transforms and opacity| ✔ | ✔ | ✔ | 31 | |Support for animating other CSS properties| ✔ | ✔ | 🚫 | 32 | |Matrix fallback for transform animations | ✔ | ✔ | 🚫 | 33 | |KeyframeEffect constructor | 🚫 | ✔ | ✔ | 34 | |Simple GroupEffects & SequenceEffects | 🚫 | ✔ | ✔ | 35 | |Custom Effects | 🚫 | ✔ | ✔ | 36 | |Timing input (easings, duration, fillMode, etc.) for groups
| 🚫 | 🚫\* | 🚫 | 37 | |Additive animation | 🚫\* | 🚫\* | 🚫 | 38 | |Motion path | 🚫\* | 🚫\* | 🚫 | 39 | |Modifiable keyframe effect timing| 🚫 | 🚫\* | 🚫\* | 40 | |Modifiable group timing | 🚫 | 🚫\* | 🚫\* | 41 | |Usable inline style\*\* | ✔ | ✔ | 🚫 | 42 | 43 | \* support is planned for these features. 44 | \*\* see inline style caveat below. 45 | 46 | Caveat: Inline style 47 | -------------------- 48 | 49 | Inline style modification is the mechanism used by the polyfill to animate 50 | properties. Both web-animations and web-animations-next incorporate a module 51 | that emulates a vanilla inline style object, so that style modification from 52 | JavaScript can still work in the presence of animations. However, to keep the 53 | size of web-animations-next-lite as small as possible, the style emulation 54 | module is not included. When using this version of the polyfill, JavaScript 55 | inline style modification will be overwritten by animations. 56 | Due to browser constraints inline style modification is not supported on iOS 7 57 | or Safari 6 (or earlier versions). 58 | 59 | -------------------------------------------------------------------------------- /docs/support.md: -------------------------------------------------------------------------------- 1 | 2 | Getting the polyfill 3 | -------------------- 4 | 5 | There are three ways to get a copy of the polyfill: 6 | 7 | 1. Download and use the `web-animations.min.js` file directly from this repository 8 | 1. Using npm: Add [`web-animations-js`](https://www.npmjs.com/package/web-animations-js) to your `package.json` 9 | 1. Using Bower: Add `web-animations/web-animations-js` to your `bower.json` 10 | 11 | Browser support 12 | --------------- 13 | 14 | The polyfill is supported on modern versions of all major browsers, including: 15 | 16 | * Chrome 56+ 17 | * Firefox 27+ 18 | * IE10+ (including Edge) 19 | * Safari (iOS) 7.1+ 20 | * Safari (Mac) 9+ 21 | 22 | In particular, the polyfill requires requestAnimationFrame. If your browser does not 23 | have requestAnimationFrame, consider loading a requestAnimationFrame polyfill first 24 | ([example](https://gist.githubusercontent.com/paulirish/1579671/raw/682e5c880c92b445650c4880a6bf9f3897ec1c5b/rAF.js)). 25 | 26 | Native fallback 27 | --------------- 28 | 29 | When the polyfill runs on a browser that implements `Element.animate()` and 30 | `Animation` playback control, it will detect and use the underlying native 31 | features for better performance. 32 | 33 | Features 34 | -------- 35 | 36 | The `web-animations.min.js` polyfill target tracks the Web Animations features 37 | that are supported natively in browsers. These include: 38 | 39 | * Element.animate() 40 | * Timing input (easings, duration, fillMode, etc.) for animation effects 41 | * Playback control (play, pause, reverse, currentTime, cancel, onfinish) 42 | * Support for animating CSS properties 43 | 44 | Caveat: Prefix handling 45 | ----------------------- 46 | 47 | The polyfill will automatically detect the correctly prefixed name to use when 48 | writing animated properties back to the platform. Where possible, the polyfill 49 | will only accept unprefixed versions of experimental features. For example: 50 | 51 | ```js 52 | element.animate({transform: ['none', 'translateX(100px)']}, 1000); 53 | ``` 54 | 55 | will work in all browsers that implement a conforming version of transform, but 56 | 57 | ```js 58 | element.animate({webkitTransform: ['none', 'translateX(100px)']}, 1000); 59 | ``` 60 | 61 | will not work anywhere. 62 | 63 | Process for breaking changes 64 | ---------------------------- 65 | 66 | When we make a potentially breaking change to the polyfill's API 67 | surface (like a rename) we will, where possible, continue supporting the 68 | old version, deprecated, for three months, and ensure that there are 69 | console warnings to indicate that a change is pending. After three 70 | months, the old version of the API surface (e.g. the old version of a 71 | function name) will be removed. *If you see deprecation warnings, you 72 | can't avoid them by not updating*. 73 | 74 | -------------------------------------------------------------------------------- /externs/README.md: -------------------------------------------------------------------------------- 1 | 2 | Closure Compiler Externs for Web Animations 3 | ------------------------------------------- 4 | 5 | This folder contains externs for using the Web Animations API with the Closure 6 | Compiler. These externs aren't strictly part of the polyfill, as they can be 7 | used for either the native or polyfilled versions. 8 | 9 | web-animations-next requires that you also include web-animations. 10 | 11 | -------------------------------------------------------------------------------- /externs/web-animations-next.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | 18 | /** 19 | * @fileoverview Basic externs for the Web Animations API (Level 2 / Groups). 20 | * This is not intended to be exhaustive, and requires the base externs from 21 | * web-animations.js. 22 | * @externs 23 | */ 24 | 25 | 26 | /** 27 | * @interface 28 | */ 29 | var AnimationEffectReadOnly = function() {}; 30 | 31 | /** @type {!AnimationEffectTiming} */ 32 | AnimationEffectReadOnly.prototype.timing; 33 | 34 | 35 | /** 36 | * @param {Element} target 37 | * @param {!Array} frames 38 | * @param {(number|AnimationEffectTimingProperties)=} opt_options 39 | * @constructor 40 | * @implements {AnimationEffectReadOnly} 41 | */ 42 | var KeyframeEffect = function(target, frames, opt_options) {}; 43 | 44 | /** 45 | * @return {!Array} 46 | */ 47 | KeyframeEffect.prototype.getFrames = function() {}; 48 | 49 | /** @type {!AnimationEffectTiming} */ 50 | KeyframeEffect.prototype.timing; 51 | 52 | /** @type {Element} */ 53 | KeyframeEffect.prototype.target; 54 | 55 | /** @type {?function(number, !KeyframeEffect, !Animation)} */ 56 | KeyframeEffect.prototype.onsample; 57 | 58 | 59 | /** 60 | * @param {!Array} children 61 | * @param {AnimationEffectTimingProperties=} opt_timing 62 | * @constructor 63 | * @implements {AnimationEffectReadOnly} 64 | */ 65 | var SequenceEffect = function(children, opt_timing) {}; 66 | 67 | /** @type {!AnimationEffectTiming} */ 68 | SequenceEffect.prototype.timing; 69 | 70 | /** @type {!Array} */ 71 | SequenceEffect.prototype.children; 72 | 73 | 74 | /** 75 | * @param {!Array} children 76 | * @param {AnimationEffectTimingProperties=} opt_timing 77 | * @constructor 78 | * @implements {AnimationEffectReadOnly} 79 | */ 80 | var GroupEffect = function(children, opt_timing) {}; 81 | 82 | /** @type {!AnimationEffectTiming} */ 83 | GroupEffect.prototype.timing; 84 | 85 | /** @type {!Array} */ 86 | GroupEffect.prototype.children; 87 | 88 | 89 | /** 90 | * @interface 91 | */ 92 | var AnimationTimeline = function() {}; 93 | 94 | /** @type {?number} */ 95 | AnimationTimeline.prototype.currentTime; 96 | 97 | /** 98 | * @param {!AnimationEffectReadOnly} effect 99 | * @return {!Animation} 100 | */ 101 | AnimationTimeline.prototype.play = function(effect) {}; 102 | 103 | /** 104 | * @interface 105 | * @extends {AnimationTimeline} 106 | */ 107 | var DocumentTimeline = function() {}; 108 | 109 | /** @type {AnimationEffectReadOnly|undefined} */ 110 | Animation.prototype.effect; 111 | 112 | /** @type {!DocumentTimeline} */ 113 | Document.prototype.timeline; 114 | -------------------------------------------------------------------------------- /externs/web-animations.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | 18 | /** 19 | * @fileoverview Basic externs for the Web Animations API. This is not 20 | * nessecarily exhaustive. For more information, see the spec- 21 | * https://drafts.csswg.org/web-animations/ 22 | * @externs 23 | */ 24 | 25 | 26 | /** 27 | * @param {!Array} frames 28 | * @param {(number|AnimationEffectTimingProperties)=} opt_options 29 | * @return {!Animation} 30 | */ 31 | Element.prototype.animate = function(frames, opt_options) {}; 32 | 33 | 34 | /** 35 | * @interface 36 | * @extends {EventTarget} 37 | */ 38 | var Animation = function() {}; 39 | 40 | /** 41 | * @return {undefined} 42 | */ 43 | Animation.prototype.cancel = function() {}; 44 | 45 | /** 46 | * @return {undefined} 47 | */ 48 | Animation.prototype.finish = function() {}; 49 | 50 | /** 51 | * @return {undefined} 52 | */ 53 | Animation.prototype.reverse = function() {}; 54 | 55 | /** 56 | * @return {undefined} 57 | */ 58 | Animation.prototype.pause = function() {}; 59 | 60 | /** 61 | * @return {undefined} 62 | */ 63 | Animation.prototype.play = function() {}; 64 | 65 | /** @type {number} */ 66 | Animation.prototype.startTime; 67 | 68 | /** @type {number} */ 69 | Animation.prototype.currentTime; 70 | 71 | /** @type {number} */ 72 | Animation.prototype.playbackRate; 73 | 74 | /** @type {string} */ 75 | Animation.prototype.playState; 76 | 77 | /** @type {?function(!Event)} */ 78 | Animation.prototype.oncancel; 79 | 80 | /** @type {?function(!Event)} */ 81 | Animation.prototype.onfinish; 82 | 83 | 84 | /** 85 | * @typedef {{ 86 | * delay: (number|undefined), 87 | * endDelay: (number|undefined), 88 | * fillMode: (string|undefined), 89 | * iterationStart: (number|undefined), 90 | * iterations: (number|undefined), 91 | * duration: (number|string|undefined), 92 | * direction: (string|undefined), 93 | * easing: (string|undefined) 94 | * }} 95 | */ 96 | var AnimationEffectTimingProperties; 97 | 98 | 99 | /** 100 | * @interface 101 | */ 102 | var AnimationEffectTiming = function() {}; 103 | 104 | /** @type {number} */ 105 | AnimationEffectTiming.prototype.delay; 106 | 107 | /** @type {number} */ 108 | AnimationEffectTiming.prototype.endDelay; 109 | 110 | /** @type {string} */ 111 | AnimationEffectTiming.prototype.fillMode; 112 | 113 | /** @type {number} */ 114 | AnimationEffectTiming.prototype.iterationStart; 115 | 116 | /** @type {number} */ 117 | AnimationEffectTiming.prototype.iterations; 118 | 119 | /** @type {number|string} */ 120 | AnimationEffectTiming.prototype.duration; 121 | 122 | /** @type {string} */ 123 | AnimationEffectTiming.prototype.direction; 124 | 125 | /** @type {string} */ 126 | AnimationEffectTiming.prototype.easing; 127 | -------------------------------------------------------------------------------- /node_modules/mocha/LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011-2014 TJ Holowaychuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-animations-js", 3 | "description": "JavaScript implementation of the Web Animations API", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/web-animations/web-animations-js.git" 7 | }, 8 | "version": "2.3.2", 9 | "keywords": [ 10 | "animations", 11 | "polyfill" 12 | ], 13 | "homepage": "https://github.com/web-animations", 14 | "license": "Apache-2.0", 15 | "main": "web-animations.min.js", 16 | "files": [ 17 | "src/*", 18 | "*.min.js", 19 | "*.min.js.map" 20 | ], 21 | "devDependencies": { 22 | "minimatch": "^3.0.4", 23 | "mocha": "1.21.4", 24 | "chai": "^1.9.1", 25 | "grunt": "~0.4.5", 26 | "grunt-contrib-uglify": "^0.4.0", 27 | "grunt-gjslint": "^0.2.1", 28 | "closure-linter-wrapper": "^1.0.0", 29 | "grunt-karma": "3.x", 30 | "karma": "4.x", 31 | "karma-mocha": "^0.1.3", 32 | "karma-chai": "^0.1.0", 33 | "karma-chrome-launcher": "~0.1.4", 34 | "karma-firefox-launcher": "~0.1.3", 35 | "karma-ie-launcher": "~0.1.5", 36 | "karma-safari-launcher": "~0.1.1", 37 | "karma-sauce-launcher": "~0.2.3", 38 | "grunt-checkrepo": "~0.1.0", 39 | "grunt-saucelabs": "~4.0.2", 40 | "grunt-git-status": "~1.0.0", 41 | "grunt-template": "~0.2.3", 42 | "source-map": "~0.1.40" 43 | }, 44 | "scripts": { 45 | "test": "grunt web-animations web-animations-next test gjslint git-status checkrepo" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/apply.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | 17 | scope.apply = function(element, property, value) { 18 | element.style[scope.propertyName(property)] = value; 19 | }; 20 | 21 | scope.clear = function(element, property) { 22 | element.style[scope.propertyName(property)] = ''; 23 | }; 24 | 25 | })(webAnimations1, webAnimationsTesting); 26 | -------------------------------------------------------------------------------- /src/box-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | function consumeLengthPercentOrAuto(string) { 17 | return scope.consumeLengthOrPercent(string) || scope.consumeToken(/^auto/, string); 18 | } 19 | function parseBox(string) { 20 | var result = scope.consumeList([ 21 | scope.ignore(scope.consumeToken.bind(null, /^rect/)), 22 | scope.ignore(scope.consumeToken.bind(null, /^\(/)), 23 | scope.consumeRepeated.bind(null, consumeLengthPercentOrAuto, /^,/), 24 | scope.ignore(scope.consumeToken.bind(null, /^\)/)), 25 | ], string); 26 | if (result && result[0].length == 4) { 27 | return result[0]; 28 | } 29 | } 30 | 31 | function mergeComponent(left, right) { 32 | if (left == 'auto' || right == 'auto') { 33 | return [true, false, function(t) { 34 | var result = t ? left : right; 35 | if (result == 'auto') { 36 | return 'auto'; 37 | } 38 | // FIXME: There's probably a better way to turn a dimension back into a string. 39 | var merged = scope.mergeDimensions(result, result); 40 | return merged[2](merged[0]); 41 | }]; 42 | } 43 | return scope.mergeDimensions(left, right); 44 | } 45 | 46 | function wrap(result) { 47 | return 'rect(' + result + ')'; 48 | } 49 | 50 | var mergeBoxes = scope.mergeWrappedNestedRepeated.bind(null, wrap, mergeComponent, ', '); 51 | 52 | scope.parseBox = parseBox; 53 | scope.mergeBoxes = mergeBoxes; 54 | 55 | scope.addPropertiesHandler(parseBox, mergeBoxes, ['clip']); 56 | 57 | })(webAnimations1, webAnimationsTesting); 58 | -------------------------------------------------------------------------------- /src/color-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | 17 | var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas'); 18 | canvas.width = canvas.height = 1; 19 | var context = canvas.getContext('2d'); 20 | 21 | function parseColor(string) { 22 | string = string.trim(); 23 | // The context ignores invalid colors 24 | context.fillStyle = '#000'; 25 | context.fillStyle = string; 26 | var contextSerializedFillStyle = context.fillStyle; 27 | context.fillStyle = '#fff'; 28 | context.fillStyle = string; 29 | if (contextSerializedFillStyle != context.fillStyle) 30 | return; 31 | context.fillRect(0, 0, 1, 1); 32 | var pixelColor = context.getImageData(0, 0, 1, 1).data; 33 | context.clearRect(0, 0, 1, 1); 34 | var alpha = pixelColor[3] / 255; 35 | return [pixelColor[0] * alpha, pixelColor[1] * alpha, pixelColor[2] * alpha, alpha]; 36 | } 37 | 38 | function mergeColors(left, right) { 39 | return [left, right, function(x) { 40 | function clamp(v) { 41 | return Math.max(0, Math.min(255, v)); 42 | } 43 | if (x[3]) { 44 | for (var i = 0; i < 3; i++) 45 | x[i] = Math.round(clamp(x[i] / x[3])); 46 | } 47 | x[3] = scope.numberToString(scope.clamp(0, 1, x[3])); 48 | return 'rgba(' + x.join(',') + ')'; 49 | }]; 50 | } 51 | 52 | scope.addPropertiesHandler(parseColor, mergeColors, 53 | ['background-color', 'border-bottom-color', 'border-left-color', 'border-right-color', 54 | 'border-top-color', 'color', 'fill', 'flood-color', 'lighting-color', 55 | 'outline-color', 'stop-color', 'stroke', 'text-decoration-color']); 56 | scope.consumeColor = scope.consumeParenthesised.bind(null, parseColor); 57 | scope.mergeColors = mergeColors; 58 | 59 | if (WEB_ANIMATIONS_TESTING) { 60 | testing.parseColor = parseColor; 61 | } 62 | 63 | })(webAnimations1, webAnimationsTesting); 64 | -------------------------------------------------------------------------------- /src/deprecation.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(shared) { 16 | 17 | var silenced = {}; 18 | 19 | shared.isDeprecated = function(feature, date, advice, plural) { 20 | if (WEB_ANIMATIONS_TESTING) { 21 | return true; 22 | } 23 | 24 | var auxVerb = plural ? 'are' : 'is'; 25 | var today = new Date(); 26 | var expiry = new Date(date); 27 | expiry.setMonth(expiry.getMonth() + 3); // 3 months grace period 28 | 29 | if (today < expiry) { 30 | if (!(feature in silenced)) { 31 | console.warn('Web Animations: ' + feature + ' ' + auxVerb + ' deprecated and will stop working on ' + expiry.toDateString() + '. ' + advice); 32 | } 33 | silenced[feature] = true; 34 | return false; 35 | } else { 36 | return true; 37 | } 38 | }; 39 | 40 | shared.deprecated = function(feature, date, advice, plural) { 41 | var auxVerb = plural ? 'are' : 'is'; 42 | if (shared.isDeprecated(feature, date, advice, plural)) { 43 | throw new Error(feature + ' ' + auxVerb + ' no longer supported. ' + advice); 44 | } 45 | }; 46 | 47 | })(webAnimationsShared); 48 | -------------------------------------------------------------------------------- /src/dev.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | var WEB_ANIMATIONS_TESTING = false; 16 | var webAnimationsTesting = null; 17 | -------------------------------------------------------------------------------- /src/effect-callback.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | (function(shared, scope, testing) { 15 | 16 | var nullTarget = document.createElementNS('http://www.w3.org/1999/xhtml', 'div'); 17 | 18 | var sequenceNumber = 0; 19 | scope.bindAnimationForCustomEffect = function(animation) { 20 | var target = animation.effect.target; 21 | var effectFunction; 22 | var isKeyframeEffect = typeof animation.effect.getFrames() == 'function'; 23 | if (isKeyframeEffect) { 24 | effectFunction = animation.effect.getFrames(); 25 | } else { 26 | effectFunction = animation.effect._onsample; 27 | } 28 | var timing = animation.effect.timing; 29 | var last = null; 30 | timing = shared.normalizeTimingInput(timing); 31 | var callback = function() { 32 | var t = callback._animation ? callback._animation.currentTime : null; 33 | if (t !== null) { 34 | t = shared.calculateIterationProgress(shared.calculateActiveDuration(timing), t, timing); 35 | if (isNaN(t)) 36 | t = null; 37 | } 38 | // FIXME: There are actually more conditions under which the effectFunction 39 | // should be called. 40 | if (t !== last) { 41 | if (isKeyframeEffect) { 42 | effectFunction(t, target, animation.effect); 43 | } else { 44 | effectFunction(t, animation.effect, animation.effect._animation); 45 | } 46 | } 47 | last = t; 48 | }; 49 | 50 | callback._animation = animation; 51 | callback._registered = false; 52 | callback._sequenceNumber = sequenceNumber++; 53 | animation._callback = callback; 54 | register(callback); 55 | }; 56 | 57 | var callbacks = []; 58 | var ticking = false; 59 | function register(callback) { 60 | if (callback._registered) 61 | return; 62 | callback._registered = true; 63 | callbacks.push(callback); 64 | if (!ticking) { 65 | ticking = true; 66 | requestAnimationFrame(tick); 67 | } 68 | } 69 | 70 | function tick(t) { 71 | var updating = callbacks; 72 | callbacks = []; 73 | updating.sort(function(left, right) { 74 | return left._sequenceNumber - right._sequenceNumber; 75 | }); 76 | updating = updating.filter(function(callback) { 77 | callback(); 78 | var playState = callback._animation ? callback._animation.playState : 'idle'; 79 | if (playState != 'running' && playState != 'pending') 80 | callback._registered = false; 81 | return callback._registered; 82 | }); 83 | callbacks.push.apply(callbacks, updating); 84 | 85 | if (callbacks.length) { 86 | ticking = true; 87 | requestAnimationFrame(tick); 88 | } else { 89 | ticking = false; 90 | } 91 | } 92 | 93 | scope.Animation.prototype._register = function() { 94 | if (this._callback) 95 | register(this._callback); 96 | }; 97 | 98 | })(webAnimationsShared, webAnimationsNext, webAnimationsTesting); 99 | -------------------------------------------------------------------------------- /src/element-animatable.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope) { 16 | window.Element.prototype.animate = function(effectInput, options) { 17 | var id = ''; 18 | if (options && options.id) { 19 | id = options.id; 20 | } 21 | return scope.timeline._play(scope.KeyframeEffect(this, effectInput, options, id)); 22 | }; 23 | })(webAnimations1); 24 | -------------------------------------------------------------------------------- /src/font-weight-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope) { 16 | function parse(string) { 17 | var out = Number(string); 18 | if (isNaN(out) || out < 100 || out > 900 || out % 100 !== 0) { 19 | return; 20 | } 21 | return out; 22 | } 23 | 24 | function toCss(value) { 25 | value = Math.round(value / 100) * 100; 26 | value = scope.clamp(100, 900, value); 27 | if (value === 400) { 28 | return 'normal'; 29 | } 30 | if (value === 700) { 31 | return 'bold'; 32 | } 33 | return String(value); 34 | } 35 | 36 | function merge(left, right) { 37 | return [left, right, toCss]; 38 | } 39 | 40 | scope.addPropertiesHandler(parse, merge, ['font-weight']); 41 | 42 | })(webAnimations1); 43 | -------------------------------------------------------------------------------- /src/interpolation.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | 17 | function interpolate(from, to, f) { 18 | if ((typeof from == 'number') && (typeof to == 'number')) { 19 | return from * (1 - f) + to * f; 20 | } 21 | if ((typeof from == 'boolean') && (typeof to == 'boolean')) { 22 | return f < 0.5 ? from : to; 23 | } 24 | 25 | WEB_ANIMATIONS_TESTING && console.assert( 26 | Array.isArray(from) && Array.isArray(to), 27 | 'If interpolation arguments are not numbers or bools they must be arrays'); 28 | 29 | if (from.length == to.length) { 30 | var r = []; 31 | for (var i = 0; i < from.length; i++) { 32 | r.push(interpolate(from[i], to[i], f)); 33 | } 34 | return r; 35 | } 36 | throw 'Mismatched interpolation arguments ' + from + ':' + to; 37 | } 38 | 39 | scope.Interpolation = function(from, to, convertToString) { 40 | return function(f) { 41 | return convertToString(interpolate(from, to, f)); 42 | } 43 | }; 44 | 45 | if (WEB_ANIMATIONS_TESTING) { 46 | testing.interpolate = interpolate; 47 | } 48 | 49 | })(webAnimations1, webAnimationsTesting); 50 | -------------------------------------------------------------------------------- /src/keyframe-effect.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(shared, scope, testing) { 16 | 17 | function EffectTime(timing) { 18 | var timeFraction = 0; 19 | var activeDuration = shared.calculateActiveDuration(timing); 20 | var effectTime = function(localTime) { 21 | return shared.calculateIterationProgress(activeDuration, localTime, timing); 22 | }; 23 | effectTime._totalDuration = timing.delay + activeDuration + timing.endDelay; 24 | return effectTime; 25 | } 26 | 27 | scope.KeyframeEffect = function(target, effectInput, timingInput, id) { 28 | var effectTime = EffectTime(shared.normalizeTimingInput(timingInput)); 29 | var interpolations = scope.convertEffectInput(effectInput); 30 | var timeFraction; 31 | var keyframeEffect = function() { 32 | WEB_ANIMATIONS_TESTING && console.assert(typeof timeFraction !== 'undefined'); 33 | interpolations(target, timeFraction); 34 | }; 35 | // Returns whether the keyframeEffect is in effect or not after the timing update. 36 | keyframeEffect._update = function(localTime) { 37 | timeFraction = effectTime(localTime); 38 | return timeFraction !== null; 39 | }; 40 | keyframeEffect._clear = function() { 41 | interpolations(target, null); 42 | }; 43 | keyframeEffect._hasSameTarget = function(otherTarget) { 44 | return target === otherTarget; 45 | }; 46 | keyframeEffect._target = target; 47 | keyframeEffect._totalDuration = effectTime._totalDuration; 48 | keyframeEffect._id = id; 49 | return keyframeEffect; 50 | }; 51 | 52 | if (WEB_ANIMATIONS_TESTING) { 53 | testing.webAnimations1KeyframeEffect = scope.KeyframeEffect; 54 | testing.effectTime = EffectTime; 55 | } 56 | 57 | })(webAnimationsShared, webAnimations1, webAnimationsTesting); 58 | -------------------------------------------------------------------------------- /src/number-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | 17 | function numberToString(x) { 18 | return x.toFixed(3).replace(/0+$/, '').replace(/\.$/, ''); 19 | } 20 | 21 | function clamp(min, max, x) { 22 | return Math.min(max, Math.max(min, x)); 23 | } 24 | 25 | function parseNumber(string) { 26 | if (/^\s*[-+]?(\d*\.)?\d+\s*$/.test(string)) 27 | return Number(string); 28 | } 29 | 30 | function mergeNumbers(left, right) { 31 | return [left, right, numberToString]; 32 | } 33 | 34 | // FIXME: This should probably go in it's own handler. 35 | function mergeFlex(left, right) { 36 | if (left == 0) 37 | return; 38 | return clampedMergeNumbers(0, Infinity)(left, right); 39 | } 40 | 41 | function mergePositiveIntegers(left, right) { 42 | return [left, right, function(x) { 43 | return Math.round(clamp(1, Infinity, x)); 44 | }]; 45 | } 46 | 47 | function clampedMergeNumbers(min, max) { 48 | return function(left, right) { 49 | return [left, right, function(x) { 50 | return numberToString(clamp(min, max, x)); 51 | }]; 52 | }; 53 | } 54 | 55 | function parseNumberList(string) { 56 | var items = string.trim().split(/\s*[\s,]\s*/); 57 | if (items.length === 0) { 58 | return; 59 | } 60 | var result = []; 61 | for (var i = 0; i < items.length; i++) { 62 | var number = parseNumber(items[i]); 63 | if (number === undefined) { 64 | return; 65 | } 66 | result.push(number); 67 | } 68 | return result; 69 | } 70 | 71 | function mergeNumberLists(left, right) { 72 | if (left.length != right.length) { 73 | return; 74 | } 75 | return [left, right, function(numberList) { 76 | return numberList.map(numberToString).join(' '); 77 | }]; 78 | } 79 | 80 | function round(left, right) { 81 | return [left, right, Math.round]; 82 | } 83 | 84 | scope.clamp = clamp; 85 | scope.addPropertiesHandler(parseNumberList, mergeNumberLists, ['stroke-dasharray']); 86 | scope.addPropertiesHandler(parseNumber, clampedMergeNumbers(0, Infinity), ['border-image-width', 'line-height']); 87 | scope.addPropertiesHandler(parseNumber, clampedMergeNumbers(0, 1), ['opacity', 'shape-image-threshold']); 88 | scope.addPropertiesHandler(parseNumber, mergeFlex, ['flex-grow', 'flex-shrink']); 89 | scope.addPropertiesHandler(parseNumber, mergePositiveIntegers, ['orphans', 'widows']); 90 | scope.addPropertiesHandler(parseNumber, round, ['z-index']); 91 | 92 | scope.parseNumber = parseNumber; 93 | scope.parseNumberList = parseNumberList; 94 | scope.mergeNumbers = mergeNumbers; 95 | scope.numberToString = numberToString; 96 | 97 | })(webAnimations1, webAnimationsTesting); 98 | -------------------------------------------------------------------------------- /src/property-names.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | 17 | var prefixed = {}; 18 | var unprefixed = {}; 19 | 20 | function alias(name, aliases) { 21 | aliases.concat([name]).forEach(function(candidate) { 22 | if (candidate in document.documentElement.style) { 23 | prefixed[name] = candidate; 24 | } 25 | unprefixed[candidate] = name; 26 | }); 27 | } 28 | alias('transform', ['webkitTransform', 'msTransform']); 29 | alias('transformOrigin', ['webkitTransformOrigin']); 30 | alias('perspective', ['webkitPerspective']); 31 | alias('perspectiveOrigin', ['webkitPerspectiveOrigin']); 32 | 33 | scope.propertyName = function(property) { 34 | return prefixed[property] || property; 35 | }; 36 | scope.unprefixedPropertyName = function(property) { 37 | return unprefixed[property] || property; 38 | }; 39 | 40 | })(webAnimations1, webAnimationsTesting); 41 | -------------------------------------------------------------------------------- /src/scope.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | var webAnimationsShared = {}; 16 | var webAnimations1 = {}; 17 | var webAnimationsNext = {}; 18 | 19 | if (!WEB_ANIMATIONS_TESTING) 20 | var webAnimationsTesting = null; 21 | -------------------------------------------------------------------------------- /src/shape-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope) { 16 | 17 | var consumeLengthOrPercent = scope.consumeParenthesised.bind(null, scope.parseLengthOrPercent); 18 | var consumeLengthOrPercentPair = scope.consumeRepeated.bind(undefined, consumeLengthOrPercent, /^/); 19 | 20 | var mergeSizePair = scope.mergeNestedRepeated.bind(undefined, scope.mergeDimensions, ' '); 21 | var mergeSizePairList = scope.mergeNestedRepeated.bind(undefined, mergeSizePair, ','); 22 | 23 | function parseShape(input) { 24 | var circle = scope.consumeToken(/^circle/, input); 25 | if (circle && circle[0]) { 26 | return ['circle'].concat(scope.consumeList([ 27 | scope.ignore(scope.consumeToken.bind(undefined, /^\(/)), 28 | consumeLengthOrPercent, 29 | scope.ignore(scope.consumeToken.bind(undefined, /^at/)), 30 | scope.consumePosition, 31 | scope.ignore(scope.consumeToken.bind(undefined, /^\)/)) 32 | ], circle[1])); 33 | } 34 | var ellipse = scope.consumeToken(/^ellipse/, input); 35 | if (ellipse && ellipse[0]) { 36 | return ['ellipse'].concat(scope.consumeList([ 37 | scope.ignore(scope.consumeToken.bind(undefined, /^\(/)), 38 | consumeLengthOrPercentPair, 39 | scope.ignore(scope.consumeToken.bind(undefined, /^at/)), 40 | scope.consumePosition, 41 | scope.ignore(scope.consumeToken.bind(undefined, /^\)/)) 42 | ], ellipse[1])); 43 | } 44 | var polygon = scope.consumeToken(/^polygon/, input); 45 | if (polygon && polygon[0]) { 46 | return ['polygon'].concat(scope.consumeList([ 47 | scope.ignore(scope.consumeToken.bind(undefined, /^\(/)), 48 | scope.optional(scope.consumeToken.bind(undefined, /^nonzero\s*,|^evenodd\s*,/), 'nonzero,'), 49 | scope.consumeSizePairList, 50 | scope.ignore(scope.consumeToken.bind(undefined, /^\)/)) 51 | ], polygon[1])); 52 | } 53 | } 54 | 55 | function mergeShapes(left, right) { 56 | if (left[0] !== right[0]) 57 | return; 58 | if (left[0] == 'circle') { 59 | return scope.mergeList(left.slice(1), right.slice(1), [ 60 | 'circle(', 61 | scope.mergeDimensions, 62 | ' at ', 63 | scope.mergeOffsetList, 64 | ')']); 65 | } 66 | if (left[0] == 'ellipse') { 67 | return scope.mergeList(left.slice(1), right.slice(1), [ 68 | 'ellipse(', 69 | scope.mergeNonNegativeSizePair, 70 | ' at ', 71 | scope.mergeOffsetList, 72 | ')']); 73 | } 74 | if (left[0] == 'polygon' && left[1] == right[1]) { 75 | return scope.mergeList(left.slice(2), right.slice(2), [ 76 | 'polygon(', 77 | left[1], 78 | mergeSizePairList, 79 | ')']); 80 | } 81 | } 82 | 83 | scope.addPropertiesHandler(parseShape, mergeShapes, ['shape-outside']); 84 | 85 | })(webAnimations1); 86 | -------------------------------------------------------------------------------- /src/timeline.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | (function(shared, scope, testing) { 17 | var originalRequestAnimationFrame = window.requestAnimationFrame; 18 | window.requestAnimationFrame = function(f) { 19 | return originalRequestAnimationFrame(function(x) { 20 | scope.timeline._updateAnimationsPromises(); 21 | f(x); 22 | scope.timeline._updateAnimationsPromises(); 23 | }); 24 | }; 25 | 26 | scope.AnimationTimeline = function() { 27 | this._animations = []; 28 | this.currentTime = undefined; 29 | }; 30 | 31 | scope.AnimationTimeline.prototype = { 32 | getAnimations: function() { 33 | this._discardAnimations(); 34 | return this._animations.slice(); 35 | }, 36 | _updateAnimationsPromises: function() { 37 | scope.animationsWithPromises = scope.animationsWithPromises.filter(function(animation) { 38 | return animation._updatePromises(); 39 | }); 40 | }, 41 | _discardAnimations: function() { 42 | this._updateAnimationsPromises(); 43 | this._animations = this._animations.filter(function(animation) { 44 | return animation.playState != 'finished' && animation.playState != 'idle'; 45 | }); 46 | }, 47 | _play: function(effect) { 48 | var animation = new scope.Animation(effect, this); 49 | this._animations.push(animation); 50 | scope.restartWebAnimationsNextTick(); 51 | // Use animation._animation.play() here, NOT animation.play(). 52 | // 53 | // Timeline.play calls new scope.Animation(effect) which (indirectly) calls Timeline.play on 54 | // effect's children, and Animation.play is also recursive. We only need to call play on each 55 | // animation in the tree once. 56 | animation._updatePromises(); 57 | animation._animation.play(); 58 | animation._updatePromises(); 59 | return animation; 60 | }, 61 | play: function(effect) { 62 | if (effect) { 63 | effect.remove(); 64 | } 65 | return this._play(effect); 66 | } 67 | }; 68 | 69 | var ticking = false; 70 | 71 | scope.restartWebAnimationsNextTick = function() { 72 | if (!ticking) { 73 | ticking = true; 74 | requestAnimationFrame(webAnimationsNextTick); 75 | } 76 | }; 77 | 78 | function webAnimationsNextTick(t) { 79 | var timeline = scope.timeline; 80 | timeline.currentTime = t; 81 | timeline._discardAnimations(); 82 | if (timeline._animations.length == 0) 83 | ticking = false; 84 | else 85 | requestAnimationFrame(webAnimationsNextTick); 86 | } 87 | 88 | var timeline = new scope.AnimationTimeline(); 89 | scope.timeline = timeline; 90 | 91 | try { 92 | Object.defineProperty(window.document, 'timeline', { 93 | configurable: true, 94 | get: function() { return timeline; } 95 | }); 96 | } catch (e) { } 97 | try { 98 | window.document.timeline = timeline; 99 | } catch (e) { } 100 | 101 | })(webAnimationsShared, webAnimationsNext, webAnimationsTesting); 102 | -------------------------------------------------------------------------------- /src/visibility-handler.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(scope, testing) { 16 | 17 | function merge(left, right) { 18 | if (left != 'visible' && right != 'visible') return; 19 | return [0, 1, function(x) { 20 | if (x <= 0) return left; 21 | if (x >= 1) return right; 22 | return 'visible'; 23 | }]; 24 | } 25 | 26 | scope.addPropertiesHandler(String, merge, ['visibility']); 27 | 28 | })(webAnimations1); 29 | 30 | -------------------------------------------------------------------------------- /src/web-animations-bonus-cancel-events.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function() { 16 | 17 | if (document.createElement('div').animate([]).oncancel !== undefined) { 18 | return; 19 | } 20 | 21 | if (WEB_ANIMATIONS_TESTING) { 22 | var now = function() { return webAnimations1.timeline.currentTime; }; 23 | } else if (window.performance && performance.now) { 24 | var now = function() { return performance.now(); }; 25 | } else { 26 | var now = function() { return Date.now(); }; 27 | } 28 | 29 | var AnimationCancelEvent = function(target, currentTime, timelineTime) { 30 | this.target = target; 31 | this.currentTime = currentTime; 32 | this.timelineTime = timelineTime; 33 | 34 | this.type = 'cancel'; 35 | this.bubbles = false; 36 | this.cancelable = false; 37 | this.currentTarget = target; 38 | this.defaultPrevented = false; 39 | this.eventPhase = Event.AT_TARGET; 40 | this.timeStamp = Date.now(); 41 | }; 42 | 43 | var originalElementAnimate = window.Element.prototype.animate; 44 | window.Element.prototype.animate = function(effectInput, options) { 45 | var animation = originalElementAnimate.call(this, effectInput, options); 46 | 47 | animation._cancelHandlers = []; 48 | animation.oncancel = null; 49 | 50 | var originalCancel = animation.cancel; 51 | animation.cancel = function() { 52 | originalCancel.call(this); 53 | var event = new AnimationCancelEvent(this, null, now()); 54 | var handlers = this._cancelHandlers.concat(this.oncancel ? [this.oncancel] : []); 55 | setTimeout(function() { 56 | handlers.forEach(function(handler) { 57 | handler.call(event.target, event); 58 | }); 59 | }, 0); 60 | }; 61 | 62 | var originalAddEventListener = animation.addEventListener; 63 | animation.addEventListener = function(type, handler) { 64 | if (typeof handler == 'function' && type == 'cancel') 65 | this._cancelHandlers.push(handler); 66 | else 67 | originalAddEventListener.call(this, type, handler); 68 | }; 69 | 70 | var originalRemoveEventListener = animation.removeEventListener; 71 | animation.removeEventListener = function(type, handler) { 72 | if (type == 'cancel') { 73 | var index = this._cancelHandlers.indexOf(handler); 74 | if (index >= 0) 75 | this._cancelHandlers.splice(index, 1); 76 | } else { 77 | originalRemoveEventListener.call(this, type, handler); 78 | } 79 | }; 80 | 81 | return animation; 82 | }; 83 | })(); 84 | -------------------------------------------------------------------------------- /src/web-animations-bonus-object-form-keyframes.js: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function(shared) { 16 | // If the polyfill is being loaded in a context where Element.animate is 17 | // supported but object-form syntax is not, then creating an animation 18 | // using the new syntax will either have no effect or will throw an exception. 19 | // In either case, we want to proceed to load this part of the polyfill. 20 | // 21 | // The test animation uses an opacity other than the one the element already 22 | // has, and doesn't need to change during the animation for the test to work. 23 | // After the test, the element's opacity will be left how we found it: 24 | // - If the animation is not created, the test will leave the element's 25 | // opacity untouched at originalOpacity. 26 | // - If the animation is created, it will be cancelled, and leave the 27 | // element's opacity at originalOpacity. 28 | // - If the animation is somehow created and runs without being cancelled, 29 | // when it finishes after 1ms, it will cease to have any effect (because 30 | // fill is not specified), and opacity will again be left at originalOpacity. 31 | var element = document.documentElement; 32 | var animation = null; 33 | var animated = false; 34 | try { 35 | var originalOpacity = getComputedStyle(element).getPropertyValue('opacity'); 36 | var testOpacity = originalOpacity == '0' ? '1' : '0'; 37 | animation = element.animate({'opacity': [testOpacity, testOpacity]}, 38 | {duration: 1}); 39 | animation.currentTime = 0; 40 | animated = getComputedStyle(element).getPropertyValue('opacity') == testOpacity; 41 | } catch (error) { 42 | } finally { 43 | if (animation) 44 | animation.cancel(); 45 | } 46 | if (animated) { 47 | return; 48 | } 49 | 50 | var originalElementAnimate = window.Element.prototype.animate; 51 | window.Element.prototype.animate = function(effectInput, options) { 52 | if (window.Symbol && Symbol.iterator && Array.prototype.from && effectInput[Symbol.iterator]) { 53 | // Handle custom iterables in most browsers by converting to an array 54 | effectInput = Array.from(effectInput); 55 | } 56 | 57 | if (!Array.isArray(effectInput) && effectInput !== null) { 58 | effectInput = shared.convertToArrayForm(effectInput); 59 | } 60 | 61 | return originalElementAnimate.call(this, effectInput, options); 62 | }; 63 | })(webAnimationsShared); 64 | -------------------------------------------------------------------------------- /target-loader.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function() { 16 | var target = webAnimationsTargetConfig.defaultTarget; 17 | if (typeof webAnimationsSourceTarget != 'undefined') 18 | target = webAnimationsSourceTarget; 19 | 20 | // Native implementation detection. 21 | 22 | var scripts = document.getElementsByTagName('script'); 23 | var location = scripts[scripts.length - 1].src.replace(/[^\/]+$/, ''); 24 | webAnimationsTargetConfig[target].src.forEach(function(sourceFile) { 25 | document.write(''); 26 | }); 27 | })(); 28 | -------------------------------------------------------------------------------- /templates/boilerplate: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | -------------------------------------------------------------------------------- /templates/runner.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 |
27 | -------------------------------------------------------------------------------- /templates/web-animations.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | <% _.forEach(src, function(src) { %> 18 | <% }); %> 19 | -------------------------------------------------------------------------------- /templates/web-animations.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | var webAnimationsSourceTarget = '<%= target %>'; 15 | var WEB_ANIMATIONS_TESTING = false; 16 | (function() { 17 | var scripts = document.getElementsByTagName('script'); 18 | var location = scripts[scripts.length - 1].src.replace(/[^\/]+$/, ''); 19 | document.write(''); 20 | document.write(''); 21 | })(); 22 | -------------------------------------------------------------------------------- /test/blink/2-keyframes-with-offsets.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 57 | -------------------------------------------------------------------------------- /test/blink/add-keyframes.html: -------------------------------------------------------------------------------- 1 | 2 | Web Animations API: Add Keyframe tests 3 | 4 | 5 |
6 |
7 | 34 | -------------------------------------------------------------------------------- /test/blink/eased-keyframes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 96 | -------------------------------------------------------------------------------- /test/blink/get-animations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 |
8 | 9 | 91 | -------------------------------------------------------------------------------- /test/blink/get-css-animations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 |
14 |
15 |
16 | 17 | 41 | -------------------------------------------------------------------------------- /test/blink/insufficient-keyframes.html: -------------------------------------------------------------------------------- 1 | 2 | Web Animations API: Insufficient Keyframe tests 3 | 4 | 5 |
6 |
7 | 40 | -------------------------------------------------------------------------------- /test/blink/interpolation/background-color-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 46 | 47 | -------------------------------------------------------------------------------- /test/blink/interpolation/background-position-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 23 | 69 | 70 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-color-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 34 | 35 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-image-outset-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 23 | 65 | 66 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-image-slice-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 43 | 44 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-image-source-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 83 | 84 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-radius-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 48 | 49 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-spacing-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 23 | 33 | 34 | 35 | 36 | 74 | 75 | -------------------------------------------------------------------------------- /test/blink/interpolation/border-width-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 34 | 35 | -------------------------------------------------------------------------------- /test/blink/interpolation/bottom-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 33 | 34 | -------------------------------------------------------------------------------- /test/blink/interpolation/box-shadow-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 64 | 65 | -------------------------------------------------------------------------------- /test/blink/interpolation/calc-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 31 | 32 | 33 | 34 | 92 | 93 | -------------------------------------------------------------------------------- /test/blink/interpolation/clip-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | 25 | 26 | 27 | 28 | 94 | -------------------------------------------------------------------------------- /test/blink/interpolation/color-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | 15 | 16 | 17 | 31 | 32 | -------------------------------------------------------------------------------- /test/blink/interpolation/flex-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 26 | 27 | 28 | 29 | 56 | 57 | -------------------------------------------------------------------------------- /test/blink/interpolation/font-size-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 22 | 23 | 24 | 25 | 55 | 56 | -------------------------------------------------------------------------------- /test/blink/interpolation/font-weight-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 47 | -------------------------------------------------------------------------------- /test/blink/interpolation/height-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 18 | 19 | 33 | 34 | -------------------------------------------------------------------------------- /test/blink/interpolation/left-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 34 | 35 | -------------------------------------------------------------------------------- /test/blink/interpolation/letter-spacing-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/list-style-image-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 18 | 19 | 20 | 21 | 84 | 85 | -------------------------------------------------------------------------------- /test/blink/interpolation/margin-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/max-height-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/max-width-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/min-height-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/min-width-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/object-position-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 84 | 85 | -------------------------------------------------------------------------------- /test/blink/interpolation/opacity-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /test/blink/interpolation/orphans-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 29 | -------------------------------------------------------------------------------- /test/blink/interpolation/outline-color-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 34 | 35 | -------------------------------------------------------------------------------- /test/blink/interpolation/outline-offset-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 35 | 36 | -------------------------------------------------------------------------------- /test/blink/interpolation/outline-width-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 47 | 48 | -------------------------------------------------------------------------------- /test/blink/interpolation/padding-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/blink/interpolation/perspective-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | 25 | 28 | 29 | 30 | 31 | 48 | 49 | -------------------------------------------------------------------------------- /test/blink/interpolation/perspective-origin-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 26 | 27 | 30 | 31 | 32 | 33 | 48 | 49 | -------------------------------------------------------------------------------- /test/blink/interpolation/right-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 21 | 34 | 35 | -------------------------------------------------------------------------------- /test/blink/interpolation/shape-image-threshold.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /test/blink/interpolation/shape-margin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 21 | 22 | -------------------------------------------------------------------------------- /test/blink/interpolation/shape-outside.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 86 | 87 | -------------------------------------------------------------------------------- /test/blink/interpolation/text-decoration-color-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 16 | 17 | 18 | 19 | 34 | 35 | -------------------------------------------------------------------------------- /test/blink/interpolation/text-indent-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 30 | 31 | -------------------------------------------------------------------------------- /test/blink/interpolation/text-shadow-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 19 | 33 | 34 | -------------------------------------------------------------------------------- /test/blink/interpolation/top-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | 20 | 33 | 34 | -------------------------------------------------------------------------------- /test/blink/interpolation/transform-none-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 26 | 27 | 30 | 31 | 32 | 33 | 76 | 77 | -------------------------------------------------------------------------------- /test/blink/interpolation/transform-origin-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 23 | 38 | 39 | -------------------------------------------------------------------------------- /test/blink/interpolation/transform-perspective-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 26 | 27 | 30 | 31 | 32 | 33 | 75 | 76 | -------------------------------------------------------------------------------- /test/blink/interpolation/transform-skew-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 26 | 27 | 30 | 31 | 32 | 33 | 62 | 63 | -------------------------------------------------------------------------------- /test/blink/interpolation/vertical-align-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 18 | 19 | 56 | 57 | -------------------------------------------------------------------------------- /test/blink/interpolation/viewport-unit-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 45 | 46 | -------------------------------------------------------------------------------- /test/blink/interpolation/visibility-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 58 | -------------------------------------------------------------------------------- /test/blink/interpolation/widows-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 30 | -------------------------------------------------------------------------------- /test/blink/interpolation/width-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 27 | 28 | 29 | 30 | 56 | 57 | -------------------------------------------------------------------------------- /test/blink/interpolation/word-spacing-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 30 | 31 | -------------------------------------------------------------------------------- /test/blink/interpolation/z-index-interpolation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 68 | 69 | -------------------------------------------------------------------------------- /test/blink/keyframe-properties.html: -------------------------------------------------------------------------------- 1 | 2 | Web Animations API: Keyframe Property tests 3 | 4 | 5 |
6 |
7 | 54 | -------------------------------------------------------------------------------- /test/blink/keyframes-with-null-offsets.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 42 | -------------------------------------------------------------------------------- /test/blink/out-of-order-keyframes.html: -------------------------------------------------------------------------------- 1 | 2 | Web Animations API: Out of order Keyframe tests 3 | 4 | 5 |
6 |
7 | 27 | -------------------------------------------------------------------------------- /test/blink/resources/blue-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web-animations/web-animations-js/480630912ad1e6e1b462363a88c0b8e93b5168fb/test/blink/resources/blue-100.png -------------------------------------------------------------------------------- /test/blink/resources/green-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web-animations/web-animations-js/480630912ad1e6e1b462363a88c0b8e93b5168fb/test/blink/resources/green-100.png -------------------------------------------------------------------------------- /test/blink/resources/green-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web-animations/web-animations-js/480630912ad1e6e1b462363a88c0b8e93b5168fb/test/blink/resources/green-20.png -------------------------------------------------------------------------------- /test/blink/resources/keyframes-test.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | function createElement() { 5 | var element = document.createElement('div'); 6 | element.style.position = 'absolute'; 7 | document.documentElement.appendChild(element); 8 | return element; 9 | } 10 | 11 | function heldTiming(progress) { 12 | return { 13 | duration: 1000, 14 | fill: 'forwards', 15 | delay: -progress * 1000, 16 | }; 17 | } 18 | 19 | function assertAnimationStyles(keyframes, expectations, description) { 20 | for (var progress in expectations) { 21 | var element = createElement(); 22 | element.animate(keyframes, heldTiming(progress)); 23 | 24 | var computedStyle = getComputedStyle(element); 25 | for (var property in expectations[progress]) { 26 | assert_equals(computedStyle[property], expectations[progress][property], 27 | property + ' at ' + (progress * 100) + '%' + (description ? ' ' + description : '')); 28 | } 29 | } 30 | } 31 | 32 | window.assertAnimationStyles = assertAnimationStyles; 33 | })(); 34 | -------------------------------------------------------------------------------- /test/blink/resources/stripes-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web-animations/web-animations-js/480630912ad1e6e1b462363a88c0b8e93b5168fb/test/blink/resources/stripes-100.png -------------------------------------------------------------------------------- /test/blink/resources/stripes-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/web-animations/web-animations-js/480630912ad1e6e1b462363a88c0b8e93b5168fb/test/blink/resources/stripes-20.png -------------------------------------------------------------------------------- /test/blink/same-offset-keyframes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 53 | -------------------------------------------------------------------------------- /test/blink/simple-keyframes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 46 | -------------------------------------------------------------------------------- /test/js/animation-cancel-event.js: -------------------------------------------------------------------------------- 1 | suite('animation-cancel-event', function() { 2 | setup(function() { 3 | this.element = document.createElement('div'); 4 | document.documentElement.appendChild(this.element); 5 | this.animation = this.element.animate([], 1000); 6 | }); 7 | teardown(function() { 8 | if (this.element.parent) 9 | this.element.removeChild(this.target); 10 | }); 11 | 12 | test('fire when animation cancelled', function(done) { 13 | var ready = false; 14 | var fired = false; 15 | var animation = this.animation; 16 | animation.oncancel = function(event) { 17 | assert(ready, 'must not be called synchronously'); 18 | assert.equal(this, animation); 19 | assert.equal(event.target, animation); 20 | assert.equal(event.currentTime, null); 21 | assert.equal(event.timelineTime, 100); 22 | if (fired) 23 | assert(false, 'must not get fired twice'); 24 | fired = true; 25 | done(); 26 | }; 27 | tick(100); 28 | animation.cancel(); 29 | tick(1100); 30 | tick(2100); 31 | ready = true; 32 | }); 33 | 34 | test('finish event must not fire when animation cancelled', function(done) { 35 | this.animation.onfinish = function(event) { 36 | assert(false, 'must not get fired'); 37 | }; 38 | this.animation.oncancel = function(event) { 39 | done(); 40 | }; 41 | tick(0); 42 | this.animation.cancel(); 43 | tick(1100); 44 | }); 45 | 46 | test('cancel event must not fire when animation finishes', function(done) { 47 | this.animation.onfinish = function(event) { 48 | done(); 49 | }; 50 | this.animation.oncancel = function(event) { 51 | assert(false, 'must not get fired'); 52 | }; 53 | tick(0); 54 | tick(1100); 55 | }); 56 | 57 | test('multiple event listeners', function(done) { 58 | var count = 0; 59 | function createHandler(expectedCount) { 60 | return function() { 61 | count++; 62 | assert.equal(count, expectedCount); 63 | }; 64 | } 65 | var toRemove = createHandler(0); 66 | this.animation.addEventListener('cancel', createHandler(1)); 67 | this.animation.addEventListener('cancel', createHandler(2)); 68 | this.animation.addEventListener('cancel', toRemove); 69 | this.animation.addEventListener('cancel', createHandler(3)); 70 | this.animation.removeEventListener('cancel', toRemove); 71 | this.animation.oncancel = function() { 72 | assert.equal(count, 3); 73 | done(); 74 | }; 75 | tick(0); 76 | this.animation.cancel(); 77 | tick(1000); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /test/js/animation-finish-event.js: -------------------------------------------------------------------------------- 1 | suite('animation-finish-event', function() { 2 | setup(function() { 3 | this.element = document.createElement('div'); 4 | document.documentElement.appendChild(this.element); 5 | this.animation = this.element.animate([], 1000); 6 | }); 7 | teardown(function() { 8 | this.element.parentNode.removeChild(this.element); 9 | }); 10 | 11 | test('fire when animation completes', function(done) { 12 | var ready = false; 13 | var fired = false; 14 | var animation = this.animation; 15 | animation.onfinish = function(event) { 16 | assert(ready, 'must not be called synchronously'); 17 | assert.equal(this, animation); 18 | assert.equal(event.target, animation); 19 | assert.equal(event.currentTime, 1000); 20 | assert.equal(event.timelineTime, 1100); 21 | if (fired) 22 | assert(false, 'must not get fired twice'); 23 | fired = true; 24 | done(); 25 | }; 26 | tick(100); 27 | tick(1100); 28 | tick(2100); 29 | ready = true; 30 | }); 31 | 32 | test('fire when reversed animation completes', function(done) { 33 | this.animation.onfinish = function(event) { 34 | assert.equal(event.currentTime, 0); 35 | assert.equal(event.timelineTime, 1001); 36 | done(); 37 | }; 38 | tick(0); 39 | tick(500); 40 | this.animation.reverse(); 41 | tick(501); 42 | tick(1001); 43 | }); 44 | 45 | test('multiple event listeners', function(done) { 46 | var count = 0; 47 | function createHandler(expectedCount) { 48 | return function() { 49 | count++; 50 | assert.equal(count, expectedCount); 51 | }; 52 | } 53 | var toRemove = createHandler(0); 54 | this.animation.addEventListener('finish', createHandler(1)); 55 | this.animation.addEventListener('finish', createHandler(2)); 56 | this.animation.addEventListener('finish', toRemove); 57 | this.animation.addEventListener('finish', createHandler(3)); 58 | this.animation.removeEventListener('finish', toRemove); 59 | this.animation.onfinish = function() { 60 | assert.equal(count, 3); 61 | done(); 62 | }; 63 | tick(0); 64 | this.animation.finish(); 65 | tick(1000); 66 | }); 67 | 68 | test('can wipe onfinish handler by setting it to null', function(done) { 69 | var finishAnimation = this.element.animate([], 1100); 70 | finishAnimation.onfinish = function(event) { 71 | done(); 72 | }; 73 | 74 | this.animation.onfinish = function(event) { 75 | assert(false, 'onfinish should be wiped'); 76 | }; 77 | this.animation.onfinish = null; 78 | tick(0); 79 | tick(1200); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /test/js/color-handler.js: -------------------------------------------------------------------------------- 1 | suite('color-handler', function() { 2 | test('parse colors', function() { 3 | assert.deepEqual(parseColor(' ReD '), [255, 0, 0, 1]); 4 | assert.deepEqual(parseColor(' magenta'), [255, 0, 255, 1]); 5 | assert.deepEqual(parseColor('transparent'), [0, 0, 0, 0]); 6 | assert.deepEqual(parseColor('#0f0'), [0, 255, 0, 1]); 7 | assert.deepEqual(parseColor('rgb(0,10,20)'), [0, 10, 20, 1]); 8 | assert.deepEqual(parseColor('rgba(65,40,20,0.2)'), [13, 8, 4, 0.2]); 9 | assert.deepEqual(parseColor('hsl(120, 100%, 50%)'), [0, 255, 0, 1]); 10 | }); 11 | test('invalid colors fail to parse', function() { 12 | assert.isUndefined(parseColor('')); 13 | assert.isUndefined(parseColor('bananayellow')); 14 | assert.isUndefined(parseColor('rgb(10, 20, 30, 40, 50)')); 15 | }); 16 | test('color interpolation', function() { 17 | assert.equal(webAnimations1.propertyInterpolation('color', '#00aa11', '#aa00bb')(0.2), 'rgba(34,136,51,1)'); 18 | assert.equal(webAnimations1.propertyInterpolation('color', 'transparent', '#004488')(0), 'transparent'); 19 | assert.equal(webAnimations1.propertyInterpolation('color', 'transparent', '#004488')(0.5), 'rgba(0,68,136,0.5)'); 20 | assert.equal(webAnimations1.propertyInterpolation('color', 'red', 'green')(2), 'rgba(0,255,0,1)'); 21 | assert.equal(webAnimations1.propertyInterpolation('color', 'red', 'green')(-1), 'rgba(255,0,0,1)'); 22 | }); 23 | test('svg color interpolation', function() { 24 | assert.equal(webAnimations1.propertyInterpolation('fill', '#00fe00', '#180036')(0.5), 'rgba(12,127,27,1)'); 25 | assert.equal(webAnimations1.propertyInterpolation('floodColor', '#00fe00', '#180036')(0.5), 'rgba(12,127,27,1)'); 26 | assert.equal(webAnimations1.propertyInterpolation('lightingColor', '#00fe00', '#180036')(0.5), 'rgba(12,127,27,1)'); 27 | assert.equal(webAnimations1.propertyInterpolation('stopColor', '#00fe00', '#180036')(0.5), 'rgba(12,127,27,1)'); 28 | assert.equal(webAnimations1.propertyInterpolation('stroke', '#00fe00', '#180036')(0.5), 'rgba(12,127,27,1)'); 29 | }); 30 | test('interpolation to/from initial', function() { 31 | assert.equal(webAnimations1.propertyInterpolation('backgroundColor', 'initial', 'red')(0.5), 'rgba(255,0,0,0.5)'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/js/effect-callback.js: -------------------------------------------------------------------------------- 1 | suite('effect-callback', function() { 2 | setup(function() { 3 | document.timeline._animations = []; 4 | webAnimations1.timeline._animations = []; 5 | }); 6 | 7 | test('animations starting in the future are not in effect', function() { 8 | var fractions = []; 9 | tick(100); 10 | var effect = new KeyframeEffect(null, [], 1000); 11 | effect.onsample = function(fraction) { 12 | fractions.push(fraction); 13 | }; 14 | var animation = document.timeline.play(effect); 15 | animation.startTime = 1000; 16 | tick(200); 17 | tick(1000); 18 | tick(1100); 19 | assert.deepEqual(fractions, [0, 0.1]); 20 | }); 21 | 22 | test('duration 0 animations get sampled at least once', function() { 23 | var timeFraction; 24 | tick(0); 25 | var effect = new KeyframeEffect(null, [], {duration: 0, fill: 'both'}); 26 | effect.onsample = function(t) { 27 | timeFraction = t; 28 | }; 29 | var animation = document.timeline.play(effect); 30 | tick(100); 31 | assert.equal(timeFraction, 1); 32 | assert.equal(isTicking(), false); 33 | }); 34 | 35 | test('animations added during custom effect callbacks get updated in the same tick', function() { 36 | var animation; 37 | var called = false; 38 | tick(0); 39 | var effect = new KeyframeEffect(null, [], 2); 40 | var effect2 = new KeyframeEffect(null, [], 1); 41 | effect.onsample = function() { 42 | animation = document.timeline.play(effect2); 43 | }; 44 | effect2.onsample = function() { 45 | called = true; 46 | }; 47 | document.timeline.play(effect); 48 | tick(1); 49 | assert.isTrue(animation.startTime >= 0); 50 | assert.isFalse(called); 51 | }); 52 | 53 | test('custom effect should be called after cancel', function() { 54 | var fractions = []; 55 | var effect = new KeyframeEffect(null, [], 1000); 56 | effect.onsample = function(fraction) { 57 | fractions.push(fraction); 58 | }; 59 | var animation = document.timeline.play(effect); 60 | tick(0); 61 | tick(500); 62 | animation.cancel(); 63 | tick(501); 64 | assert.deepEqual(fractions, [0, 0.5, null]); 65 | }); 66 | 67 | test('Custom callback is given effect and animation', function() { 68 | var callbackEffect; 69 | var callbackAnim; 70 | var effect = new KeyframeEffect(document.body, [], 100); 71 | effect.onsample = function(t, e, a) { 72 | callbackEffect = e; 73 | callbackAnim = a; 74 | }; 75 | var animation = document.timeline.play(effect); 76 | tick(50); 77 | tick(150); 78 | assert.equal(isTicking(), false); 79 | assert.equal(callbackAnim, animation); 80 | assert.equal(callbackEffect.target, document.body); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /test/js/group-animation-cancel-event.js: -------------------------------------------------------------------------------- 1 | suite('group-animation-cancel-event', function() { 2 | setup(function() { 3 | document.timeline.currentTime = undefined; 4 | this.element = document.createElement('div'); 5 | document.documentElement.appendChild(this.element); 6 | var sequenceEffect = new SequenceEffect([ 7 | new KeyframeEffect(this.element, [], 500), 8 | new GroupEffect([ 9 | new KeyframeEffect(this.element, [], 250), 10 | new KeyframeEffect(this.element, [], 500), 11 | ]), 12 | ]); 13 | this.animation = document.timeline.play(sequenceEffect, 1000); 14 | }); 15 | teardown(function() { 16 | if (this.element.parent) 17 | this.element.removeChild(this.element); 18 | }); 19 | 20 | test('fire when animation cancelled', function(done) { 21 | var ready = false; 22 | var fired = false; 23 | var animation = this.animation; 24 | animation.oncancel = function(event) { 25 | assert(ready, 'must not be called synchronously'); 26 | assert.equal(this, animation); 27 | assert.equal(event.target, animation); 28 | assert.equal(event.currentTime, null); 29 | assert.equal(event.timelineTime, 100); 30 | if (fired) 31 | assert(false, 'must not get fired twice'); 32 | fired = true; 33 | done(); 34 | }; 35 | tick(100); 36 | animation.cancel(); 37 | tick(1100); 38 | tick(2100); 39 | ready = true; 40 | }); 41 | 42 | test('finish event must not fire when animation cancelled', function(done) { 43 | this.animation.onfinish = function(event) { 44 | assert(false, 'must not get fired'); 45 | }; 46 | this.animation.oncancel = function(event) { 47 | done(); 48 | }; 49 | tick(0); 50 | this.animation.cancel(); 51 | tick(1100); 52 | }); 53 | 54 | test('cancel event must not fire when animation finishes', function(done) { 55 | this.animation.onfinish = function(event) { 56 | done(); 57 | }; 58 | this.animation.oncancel = function(event) { 59 | assert(false, 'must not get fired'); 60 | }; 61 | tick(0); 62 | tick(1100); 63 | }); 64 | 65 | test('multiple event listeners', function(done) { 66 | var count = 0; 67 | function createHandler(expectedCount) { 68 | return function() { 69 | count++; 70 | assert.equal(count, expectedCount); 71 | }; 72 | } 73 | var toRemove = createHandler(0); 74 | this.animation.addEventListener('cancel', createHandler(1)); 75 | this.animation.addEventListener('cancel', createHandler(2)); 76 | this.animation.addEventListener('cancel', toRemove); 77 | this.animation.addEventListener('cancel', createHandler(3)); 78 | this.animation.removeEventListener('cancel', toRemove); 79 | this.animation.oncancel = function() { 80 | assert.equal(count, 3); 81 | done(); 82 | }; 83 | tick(0); 84 | this.animation.cancel(); 85 | tick(1000); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /test/js/group-animation-finish-event.js: -------------------------------------------------------------------------------- 1 | suite('group-animation-finish-event', function() { 2 | setup(function() { 3 | document.timeline.currentTime = undefined; 4 | this.element = document.createElement('div'); 5 | document.documentElement.appendChild(this.element); 6 | var sequenceEffect = new SequenceEffect([ 7 | new KeyframeEffect(this.element, [], 500), 8 | new GroupEffect([ 9 | new KeyframeEffect(this.element, [], 250), 10 | new KeyframeEffect(this.element, [], 500), 11 | ]), 12 | ]); 13 | this.animation = document.timeline.play(sequenceEffect, 1000); 14 | }); 15 | teardown(function() { 16 | this.element.parentNode.removeChild(this.element); 17 | }); 18 | 19 | test('fire when animation completes', function(done) { 20 | var ready = false; 21 | var fired = false; 22 | var animation = this.animation; 23 | animation.onfinish = function(event) { 24 | assert(ready, 'must not be called synchronously'); 25 | assert.equal(this, animation); 26 | assert.equal(event.target, animation); 27 | assert.equal(event.currentTime, 1000); 28 | assert.equal(event.timelineTime, 1100); 29 | if (fired) 30 | assert(false, 'must not get fired twice'); 31 | fired = true; 32 | done(); 33 | }; 34 | tick(100); 35 | tick(1100); 36 | tick(2100); 37 | ready = true; 38 | }); 39 | 40 | test('fire when reversed animation completes', function(done) { 41 | this.animation.onfinish = function(event) { 42 | assert.equal(event.currentTime, 0); 43 | assert.equal(event.timelineTime, 1001); 44 | done(); 45 | }; 46 | tick(0); 47 | tick(500); 48 | this.animation.reverse(); 49 | tick(501); 50 | tick(1001); 51 | }); 52 | 53 | test('multiple event listeners', function(done) { 54 | var count = 0; 55 | function createHandler(expectedCount) { 56 | return function() { 57 | count++; 58 | assert.equal(count, expectedCount); 59 | }; 60 | } 61 | var toRemove = createHandler(0); 62 | this.animation.addEventListener('finish', createHandler(1)); 63 | this.animation.addEventListener('finish', createHandler(2)); 64 | this.animation.addEventListener('finish', toRemove); 65 | this.animation.addEventListener('finish', createHandler(3)); 66 | this.animation.removeEventListener('finish', toRemove); 67 | this.animation.onfinish = function() { 68 | assert.equal(count, 3); 69 | done(); 70 | }; 71 | tick(0); 72 | this.animation.finish(); 73 | tick(1000); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /test/js/interpolation.js: -------------------------------------------------------------------------------- 1 | suite('interpolation', function() { 2 | test('interpolate numbers', function() { 3 | assert.equal(interpolate(4, 2, 0.2), 3.6); 4 | }); 5 | test('interpolate bools', function() { 6 | assert.equal(interpolate(false, true, 0.4), false); 7 | assert.equal(interpolate(false, true, 0.5), true); 8 | assert.equal(interpolate(false, true, 0.5), true); 9 | }); 10 | test('interpolate lists', function() { 11 | assert.deepEqual(interpolate([1, 2, 3], [4, 5, 6], 0.5), [2.5, 3.5, 4.5]); 12 | assert.deepEqual(interpolate([1], [4], 0.6), [2.8]); 13 | assert.deepEqual(interpolate([false], [true], 0.6), [true]); 14 | assert.deepEqual(interpolate([1, false, [3, 6]], [4, true, [6, 8]], 0.6), [2.8, true, [4.8, 7.2]]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/js/number-handler.js: -------------------------------------------------------------------------------- 1 | suite('number-handler', function() { 2 | test('parse numbers', function() { 3 | var tests = { 4 | '0': 0, 5 | '1234': 1234, 6 | '-40': -40, 7 | '+40': 40, 8 | ' -40 ': -40, 9 | '4.0': 4, 10 | '0.4': 0.4, 11 | '.1234': 0.1234, 12 | '12.34': 12.34, 13 | '+.1234': 0.1234, 14 | '+12.34': 12.34, 15 | '-.1234': -0.1234, 16 | '-12.34': -12.34, 17 | }; 18 | for (var string in tests) { 19 | assert.equal(webAnimations1.parseNumber(string), tests[string], 'Parsing "' + string + '"'); 20 | } 21 | }); 22 | test('number list interpolation', function() { 23 | assert.equal(webAnimations1.propertyInterpolation('strokeDasharray', '10', '20')(0.25), '12.5'); 24 | assert.equal(webAnimations1.propertyInterpolation('strokeDasharray', '10 100', '20 200')(0.25), '12.5 125'); 25 | assert.equal(webAnimations1.propertyInterpolation('strokeDasharray', '10, 100', '20, 200')(0.25), '12.5 125'); 26 | assert.equal(webAnimations1.propertyInterpolation('strokeDasharray', '10,100', '20 200')(0.25), '12.5 125'); 27 | }); 28 | test('invalid numbers fail to parse', function() { 29 | assert.isUndefined(webAnimations1.parseNumber('')); 30 | assert.isUndefined(webAnimations1.parseNumber('nine')); 31 | assert.isUndefined(webAnimations1.parseNumber('1 2')); 32 | assert.isUndefined(webAnimations1.parseNumber('+-0')); 33 | assert.isUndefined(webAnimations1.parseNumber('50px')); 34 | assert.isUndefined(webAnimations1.parseNumber('1.2.3')); 35 | assert.isUndefined(webAnimations1.parseNumberList('10,,20')); 36 | }); 37 | test('opacity clamping', function() { 38 | var interpolation = webAnimations1.propertyInterpolation('opacity', '0', '1'); 39 | assert.equal(interpolation(-1), '0'); 40 | assert.equal(interpolation(2), '1'); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/js/property-interpolation.js: -------------------------------------------------------------------------------- 1 | suite('property-interpolation', function() { 2 | test('unmatched inputs return step interpolation', function() { 3 | tests = [['unknown', 'input', 'tuple'], 4 | ['unknown', '10px', '50px'], 5 | ['width', '100px', 'auto'], 6 | ['width', 'auto', '100px']]; 7 | for (var i = 0; i < tests.length; i++) { 8 | var property = tests[i][0]; 9 | var left = tests[i][1]; 10 | var right = tests[i][2]; 11 | interpolation = webAnimations1.propertyInterpolation(property, left, right); 12 | assert.equal(interpolation(-1), left); 13 | assert.equal(interpolation(0), left); 14 | assert.equal(interpolation(0.45), left); 15 | assert.equal(interpolation(0.5), right); 16 | assert.equal(interpolation(0.55), right); 17 | assert.equal(interpolation(1), right); 18 | assert.equal(interpolation(2), right); 19 | } 20 | }); 21 | 22 | test('registers camel cased property names', function() { 23 | function merge(a, b) { 24 | return [a, b, function(x) { return a + b; }]; 25 | }; 26 | webAnimations1.addPropertiesHandler(Number, merge, ['dummy-property']); 27 | assert.equal(webAnimations1.propertyInterpolation('dummyProperty', 5, 3)(0.5), 8); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/js/tick.js: -------------------------------------------------------------------------------- 1 | suite('tick-tests', function() { 2 | setup(function() { webAnimations1.timeline._animations = []; }); 3 | 4 | test('animations are in effect but ticking stops once forward fill is reached', function() { 5 | tick(90); 6 | var animation = document.body.animate([], {duration: 1000, fill: 'forwards'}); 7 | tick(100); 8 | tick(600); 9 | assert.equal(webAnimations1.timeline._animations.length, 1); 10 | assert.equal(isTicking(), true); 11 | tick(1100); 12 | assert.equal(animation.playState, 'finished'); 13 | assert.equal(webAnimations1.timeline._animations.length, 1); 14 | assert.equal(isTicking(), false); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/js/timeline.js: -------------------------------------------------------------------------------- 1 | suite('timeline-tests', function() { 2 | setup(function() { 3 | document.timeline._animations = []; 4 | webAnimations1.timeline._animation = []; 5 | }); 6 | 7 | test('no current animations', function() { 8 | assert.equal(document.timeline.getAnimations().length, 0); 9 | }); 10 | 11 | test('timeline.play with null argument', function() { 12 | assert.notEqual(document.timeline.play(), null); 13 | }); 14 | 15 | test('getAnimations', function() { 16 | tick(90); 17 | assert.equal(document.timeline.getAnimations().length, 0); 18 | var animation = document.body.animate([], {duration: 500, iterations: 1}); 19 | tick(300); 20 | assert.equal(document.timeline.getAnimations().length, 1); 21 | 22 | var animation2 = document.body.animate([], {duration: 1000}); 23 | assert.equal(document.timeline.getAnimations().length, 2); 24 | tick(800); 25 | assert.equal(animation.playState, 'finished'); 26 | assert.equal(document.timeline.getAnimations().length, 1); 27 | tick(2000); 28 | assert.equal(document.timeline.getAnimations().length, 0); 29 | }); 30 | 31 | test('getAnimations checks cancelled animation', function() { 32 | tick(90); 33 | assert.equal(document.timeline.getAnimations().length, 0); 34 | var animation = document.body.animate([], {duration: 500, iterations: 1}); 35 | tick(300); 36 | assert.equal(document.timeline.getAnimations().length, 1); 37 | animation.cancel(); 38 | assert.equal(document.timeline.getAnimations().length, 0); 39 | }); 40 | 41 | test('playing a finished animation puts it back in the timeline', function() { 42 | tick(0); 43 | assert.equal(document.timeline.getAnimations().length, 0); 44 | var animation = document.body.animate([], {duration: 500, iterations: 1}); 45 | tick(1); 46 | tick(300); 47 | assert.equal(document.timeline.getAnimations().length, 1); 48 | tick(700); 49 | assert.equal(document.timeline.getAnimations().length, 0); 50 | animation.play(); 51 | assert.equal(document.timeline.getAnimations().length, 1); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /test/js/timing.js: -------------------------------------------------------------------------------- 1 | suite('timing', function() { 2 | test('pause and scrub', function() { 3 | var animation = document.body.animate([], { duration: 1000 }); 4 | animation.pause(); 5 | 6 | animation.currentTime = 500; 7 | assert.equal(animation.currentTime, 500); 8 | }); 9 | 10 | test('pause, scrub and play', function() { 11 | var target = document.createElement('div'); 12 | document.body.appendChild(target); 13 | 14 | var animation = target.animate([ 15 | { background: 'blue' }, 16 | { background: 'red' } 17 | ], { duration: 1000 }); 18 | tick(100); 19 | animation.pause(); 20 | 21 | animation.currentTime = 200; 22 | // http://www.w3.org/TR/web-animations/#the-current-time-of-an-animation 23 | // currentTime should now mean 'hold time' - this allows scrubbing. 24 | assert.equal(animation.currentTime, 200); 25 | animation.play(); 26 | 27 | tick(200); 28 | tick(300); 29 | assert.equal(animation.currentTime, 300); 30 | assert.equal(animation.startTime, 0); 31 | }); 32 | 33 | test('sanity-check NaN timing', function() { 34 | // This has no actual tests, but will infinite loop without fix. 35 | 36 | var animation = document.body.animate([], { 37 | duration: 2000, 38 | easing: 'ease-in' // fails only with cubic easing, not linear 39 | }); 40 | tick(100); 41 | animation.currentTime = NaN; 42 | tick(200); 43 | 44 | animation = document.body.animate([], { duration: NaN, easing: 'ease-out' }); 45 | tick(300); 46 | }); 47 | 48 | test('can set fill:none on group', function() { 49 | var timing = webAnimationsShared.makeTiming({fill: 'none'}, true); 50 | assert.equal(timing.fill, 'none'); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /test/js/visibility-handler.js: -------------------------------------------------------------------------------- 1 | suite('visibility-handler', function() { 2 | test('visibility interpolation', function() { 3 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'visible', 'hidden')(-1), 'visible'); 4 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'visible', 'hidden')(0), 'visible'); 5 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'visible', 'hidden')(0.9), 'visible'); 6 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'visible', 'hidden')(1), 'hidden'); 7 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'visible', 'hidden')(2), 'hidden'); 8 | 9 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'collapse')(-1), 'hidden'); 10 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'collapse')(0), 'hidden'); 11 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'collapse')(0.4), 'hidden'); 12 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'collapse')(0.6), 'collapse'); 13 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'collapse')(1), 'collapse'); 14 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'collapse')(2), 'collapse'); 15 | 16 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'collapse', 'visible')(-1), 'collapse'); 17 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'collapse', 'visible')(0), 'collapse'); 18 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'collapse', 'visible')(0.1), 'visible'); 19 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'collapse', 'visible')(1), 'visible'); 20 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'collapse', 'visible')(2), 'visible'); 21 | }); 22 | test('interpolation to/from initial', function() { 23 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'initial', 'collapse')(0.9), 'visible'); 24 | assert.equal(webAnimations1.propertyInterpolation('visibility', 'hidden', 'initial')(0.1), 'visible'); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/karma-config-ci.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | var customLaunchers = { 3 | sl_chrome: { 4 | base: 'SauceLabs', 5 | browserName: 'chrome', 6 | platform: 'Windows 7' 7 | }, 8 | sl_firefox: { 9 | base: 'SauceLabs', 10 | browserName: 'firefox', 11 | version: '27' 12 | }, 13 | sl_ios_safari: { 14 | base: 'SauceLabs', 15 | browserName: 'iphone', 16 | platform: 'OS X 10.9', 17 | version: '7.1' 18 | }, 19 | sl_ie_11: { 20 | base: 'SauceLabs', 21 | browserName: 'internet explorer', 22 | platform: 'Windows 8.1', 23 | version: '11' 24 | } 25 | }; 26 | 27 | config.set({ 28 | frameworks: ['mocha', 'chai'], 29 | plugins: [ 30 | 'karma-mocha', 31 | 'karma-chai', 32 | 'karma-sauce-launcher', 33 | ], 34 | sauceLabs: { 35 | testName: 'Web App Unit Tests' 36 | }, 37 | customLaunchers: customLaunchers, 38 | browsers: Object.keys(customLaunchers), 39 | basePath: '..', 40 | files: [ 41 | // Populated in `grunt test` task. 42 | ], 43 | singleRun: true, 44 | port: 9876, 45 | reporters: ['dots', 'saucelabs'], 46 | colors: true, 47 | autoWatch: false, 48 | captureTimeout: 300000, 49 | }); 50 | }; 51 | -------------------------------------------------------------------------------- /test/karma-config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | // The following config properties are populated by grunt: 4 | // frameworks, plugins, files. 5 | plugins: [ 6 | 'karma-firefox-launcher' 7 | ], 8 | browsers: ['Firefox'], 9 | basePath: '..', 10 | port: 9876, 11 | reporters: ['dots'], 12 | colors: true, 13 | autoWatch: false, 14 | proxies: { 15 | '/resources/': '/base/test/web-platform-tests/resources/', 16 | 17 | // Using our own augmented testharnessreport.js that talks with karma-testharness-adapter.js 18 | '/resources/testharnessreport.js': '/base/test/resources/testharnessreport.js', 19 | 20 | // Matching behaviour of WPT's serve tool: https://github.com/w3c/wpt-tools/blob/de648409ff2556576d59810b3ba971aeac2184a2/serve/serve.py#L45 21 | '/resources/WebIDLParser.js': '/base/test/web-platform-tests/resources/webidl2/lib/webidl2.js', 22 | 23 | '/test/': '/base/test/', 24 | }, 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /test/karma-mocha-setup.js: -------------------------------------------------------------------------------- 1 | var WEB_ANIMATIONS_TESTING = true; 2 | var webAnimationsTesting = window; 3 | var assert = chai.assert; 4 | mocha.setup({ ui: 'tdd' }); 5 | 6 | (function() { 7 | 8 | var pageError = null; 9 | 10 | addEventListener('error', function(event) { 11 | pageError = event.filename + ':' + event.lineno + ' ' + event.message; 12 | }); 13 | 14 | addEventListener('load', function() { 15 | 16 | // Inject test suite for page errors if any encountered. 17 | if (pageError) { 18 | suite('page-script-errors', function() { 19 | test('no script errors on page', function() { 20 | assert.fail(null, null, pageError); 21 | }); 22 | }); 23 | } 24 | }); 25 | 26 | })(); 27 | -------------------------------------------------------------------------------- /test/runner-web-animations-next-lite.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 |
27 | -------------------------------------------------------------------------------- /test/runner-web-animations-next.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 |
27 | -------------------------------------------------------------------------------- /test/runner-web-animations.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 26 |
27 | -------------------------------------------------------------------------------- /test/runner.js: -------------------------------------------------------------------------------- 1 | var WEB_ANIMATIONS_TESTING = true; 2 | var webAnimationsTesting = window; 3 | var assert = chai.assert; 4 | mocha.setup({ ui: 'tdd' }); 5 | 6 | function loadWebAnimationsBuildTarget(target) { 7 | var config = webAnimationsTargetConfig[target]; 8 | config.src.concat(config.test).forEach(function(file) { 9 | document.write('\n'); 10 | }); 11 | } 12 | 13 | (function() { 14 | 15 | var pageError = null; 16 | 17 | addEventListener('error', function(event) { 18 | pageError = event.filename + ':' + event.lineno + ' ' + event.message; 19 | }); 20 | 21 | addEventListener('load', function() { 22 | 23 | // Inject test suite for page errors if any encountered. 24 | if (pageError) { 25 | suite('page-script-errors', function() { 26 | test('no script errors on page', function() { 27 | assert.fail(null, null, pageError); 28 | }); 29 | }); 30 | } 31 | 32 | mocha.run(); 33 | }); 34 | 35 | })(); 36 | -------------------------------------------------------------------------------- /test/testharness-runner.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | -------------------------------------------------------------------------------- /test/testharness-runner.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | (function() { 16 | var assert = chai.assert; 17 | mocha.setup({ ui: 'tdd' }); 18 | 19 | var iframe; 20 | function defineTestharnessTest(shouldPass, testFile) { 21 | var name = shouldPass ? testFile : 'Expected Failure: ' + testFile; 22 | test(name, function(done) { 23 | window.initTestHarness = function(child) { 24 | child.add_completion_callback(function(tests, harness_status) { 25 | var failures = tests.filter(function(result) { 26 | return result.status != 0; 27 | }).map(function(failure) { 28 | return failure.name + ':\n' + failure.message; 29 | }); 30 | var error; 31 | if (shouldPass && failures.length) { 32 | error = new Error('\n' + failures.join('\n\n')); 33 | error.stack = null; 34 | } else if (!shouldPass && failures.length == 0) { 35 | error = new Error('\nExpected to fail, but passed'); 36 | error.stack = null; 37 | } 38 | done(error); 39 | }); 40 | }; 41 | iframe.src = testFile; 42 | }); 43 | } 44 | 45 | suite('testharness tests', function() { 46 | setup(function() { 47 | iframe = document.createElement('iframe'); 48 | document.body.appendChild(iframe); 49 | }); 50 | teardown(function() { 51 | iframe.parentNode.removeChild(iframe); 52 | }); 53 | testHarnessTests.forEach(defineTestharnessTest.bind(null, true)); 54 | testHarnessFailures.forEach(defineTestharnessTest.bind(null, false)); 55 | }); 56 | 57 | suite('interpolation tests', function() { 58 | setup(function() { 59 | iframe = document.createElement('iframe'); 60 | document.body.appendChild(iframe); 61 | }); 62 | teardown(function() { 63 | iframe.parentNode.removeChild(iframe); 64 | }); 65 | interpolationTests.forEach(defineTestharnessTest.bind(null, true)); 66 | interpolationFailures.forEach(defineTestharnessTest.bind(null, false)); 67 | }); 68 | 69 | addEventListener('load', function() { 70 | mocha.run(); 71 | }); 72 | })(); 73 | -------------------------------------------------------------------------------- /web-animations-next-lite.dev.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /web-animations-next-lite.dev.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | var webAnimationsSourceTarget = 'web-animations-next-lite'; 15 | var WEB_ANIMATIONS_TESTING = false; 16 | (function() { 17 | var scripts = document.getElementsByTagName('script'); 18 | var location = scripts[scripts.length - 1].src.replace(/[^\/]+$/, ''); 19 | document.write(''); 20 | document.write(''); 21 | })(); 22 | -------------------------------------------------------------------------------- /web-animations-next-lite.min.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web-animations-next.dev.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /web-animations-next.dev.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | var webAnimationsSourceTarget = 'web-animations-next'; 15 | var WEB_ANIMATIONS_TESTING = false; 16 | (function() { 17 | var scripts = document.getElementsByTagName('script'); 18 | var location = scripts[scripts.length - 1].src.replace(/[^\/]+$/, ''); 19 | document.write(''); 20 | document.write(''); 21 | })(); 22 | -------------------------------------------------------------------------------- /web-animations-next.min.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web-animations.dev.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /web-animations.dev.js: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | var webAnimationsSourceTarget = 'web-animations'; 15 | var WEB_ANIMATIONS_TESTING = false; 16 | (function() { 17 | var scripts = document.getElementsByTagName('script'); 18 | var location = scripts[scripts.length - 1].src.replace(/[^\/]+$/, ''); 19 | document.write(''); 20 | document.write(''); 21 | })(); 22 | -------------------------------------------------------------------------------- /web-animations.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /web-animations.min.html: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------