<!-- Copyright (c) 2015 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="animations/opaque-animation.html"> <script> /** * `Polymer.NeonAnimatableBehavior` is implemented by elements containing animations for use with * elements implementing `Polymer.NeonAnimationRunnerBehavior`. * @polymerBehavior */ Polymer.NeonAnimatableBehavior = { properties: { /** * Animation configuration. See README for more info. */ animationConfig: { type: Object }, /** * Convenience property for setting an 'entry' animation. Do not set `animationConfig.entry` * manually if using this. The animated node is set to `this` if using this property. */ entryAnimation: { observer: '_entryAnimationChanged', type: String }, /** * Convenience property for setting an 'exit' animation. Do not set `animationConfig.exit` * manually if using this. The animated node is set to `this` if using this property. */ exitAnimation: { observer: '_exitAnimationChanged', type: String } }, _entryAnimationChanged: function() { this.animationConfig = this.animationConfig || {}; if (this.entryAnimation !== 'fade-in-animation') { // insert polyfill hack this.animationConfig['entry'] = [{ name: 'opaque-animation', node: this }, { name: this.entryAnimation, node: this }]; } else { this.animationConfig['entry'] = [{ name: this.entryAnimation, node: this }]; } }, _exitAnimationChanged: function() { this.animationConfig = this.animationConfig || {}; this.animationConfig['exit'] = [{ name: this.exitAnimation, node: this }]; }, _copyProperties: function(config1, config2) { // shallowly copy properties from config2 to config1 for (var property in config2) { config1[property] = config2[property]; } }, _cloneConfig: function(config) { var clone = { isClone: true }; this._copyProperties(clone, config); return clone; }, _getAnimationConfigRecursive: function(type, map, allConfigs) { if (!this.animationConfig) { return; } // type is optional var thisConfig; if (type) { thisConfig = this.animationConfig[type]; } else { thisConfig = this.animationConfig; } if (!Array.isArray(thisConfig)) { thisConfig = [thisConfig]; } // iterate animations and recurse to process configurations from child nodes if (thisConfig) { for (var config, index = 0; config = thisConfig[index]; index++) { if (config.animatable) { config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs); } else { if (config.id) { var cachedConfig = map[config.id]; if (cachedConfig) { // merge configurations with the same id, making a clone lazily if (!cachedConfig.isClone) { map[config.id] = this._cloneConfig(cachedConfig) cachedConfig = map[config.id]; } this._copyProperties(cachedConfig, config); } else { // put any configs with an id into a map map[config.id] = config; } } else { allConfigs.push(config); } } } } }, /** * An element implementing `Polymer.NeonAnimationRunnerBehavior` calls this method to configure * an animation with an optional type. Elements implementing `Polymer.NeonAnimatableBehavior` * should define the property `animationConfig`, which is either a configuration object * or a map of animation type to array of configuration objects. */ getAnimationConfig: function(type) { var map = []; var allConfigs = []; this._getAnimationConfigRecursive(type, map, allConfigs); // append the configurations saved in the map to the array for (var key in map) { allConfigs.push(map[key]); } return allConfigs; } }; </script>