| <!-- |
| @license |
| 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="../iron-resizable-behavior/iron-resizable-behavior.html"> |
| <link rel="import" href="../iron-selector/iron-selectable.html"> |
| <link rel="import" href="neon-animation-runner-behavior.html"> |
| |
| <!-- |
| Material design: [Meaningful transitions](https://www.google.com/design/spec/animation/meaningful-transitions.html) |
| |
| `neon-animated-pages` manages a set of pages and runs an animation when switching between them. Its |
| children pages should implement `Polymer.NeonAnimatableBehavior` and define `entry` and `exit` |
| animations to be run when switching to or switching out of the page. |
| |
| @group Neon Elements |
| @element neon-animated-pages |
| @demo demo/index.html |
| --> |
| |
| <dom-module id="neon-animated-pages"> |
| <template> |
| <style> |
| :host { |
| display: block; |
| position: relative; |
| } |
| |
| :host > ::content > * { |
| position: absolute; |
| top: 0; |
| left: 0; |
| bottom: 0; |
| right: 0; |
| } |
| |
| :host > ::content > :not(.iron-selected):not(.neon-animating) { |
| display: none !important; |
| } |
| |
| :host > ::content > .neon-animating { |
| pointer-events: none; |
| } |
| </style> |
| |
| <content id="content"></content> |
| </template> |
| |
| </dom-module> |
| |
| <script> |
| (function() { |
| |
| Polymer({ |
| |
| is: 'neon-animated-pages', |
| |
| behaviors: [ |
| Polymer.IronResizableBehavior, |
| Polymer.IronSelectableBehavior, |
| Polymer.NeonAnimationRunnerBehavior |
| ], |
| |
| properties: { |
| |
| activateEvent: { |
| type: String, |
| value: '' |
| }, |
| |
| // if true, the initial page selection will also be animated according to its animation config. |
| animateInitialSelection: { |
| type: Boolean, |
| value: false |
| } |
| |
| }, |
| |
| listeners: { |
| 'iron-select': '_onIronSelect', |
| 'neon-animation-finish': '_onNeonAnimationFinish' |
| }, |
| |
| _onIronSelect: function(event) { |
| var selectedPage = event.detail.item; |
| |
| // Only consider child elements. |
| if (this.items.indexOf(selectedPage) < 0) { |
| return; |
| } |
| |
| var oldPage = this._valueToItem(this._prevSelected) || false; |
| this._prevSelected = this.selected; |
| |
| // on initial load and if animateInitialSelection is negated, simply display selectedPage. |
| if (!oldPage && !this.animateInitialSelection) { |
| this._completeSelectedChanged(); |
| return; |
| } |
| |
| this.animationConfig = []; |
| |
| // configure selectedPage animations. |
| if (this.entryAnimation) { |
| this.animationConfig.push({ |
| name: this.entryAnimation, |
| node: selectedPage |
| }); |
| } else { |
| if (selectedPage.getAnimationConfig) { |
| this.animationConfig.push({ |
| animatable: selectedPage, |
| type: 'entry' |
| }); |
| } |
| } |
| |
| // configure oldPage animations iff exists. |
| if (oldPage) { |
| |
| // cancel the currently running animation if one is ongoing. |
| if (oldPage.classList.contains('neon-animating')) { |
| this._squelchNextFinishEvent = true; |
| this.cancelAnimation(); |
| this._completeSelectedChanged(); |
| this._squelchNextFinishEvent = false; |
| } |
| |
| // configure the animation. |
| if (this.exitAnimation) { |
| this.animationConfig.push({ |
| name: this.exitAnimation, |
| node: oldPage |
| }); |
| } else { |
| if (oldPage.getAnimationConfig) { |
| this.animationConfig.push({ |
| animatable: oldPage, |
| type: 'exit' |
| }); |
| } |
| } |
| |
| // display the oldPage during the transition. |
| oldPage.classList.add('neon-animating'); |
| } |
| |
| // display the selectedPage during the transition. |
| selectedPage.classList.add('neon-animating'); |
| |
| // actually run the animations. |
| if (this.animationConfig.length >= 1) { |
| |
| // on first load, ensure we run animations only after element is attached. |
| if (!this.isAttached) { |
| this.async(function () { |
| this.playAnimation(undefined, { |
| fromPage: null, |
| toPage: selectedPage |
| }); |
| }); |
| |
| } else { |
| this.playAnimation(undefined, { |
| fromPage: oldPage, |
| toPage: selectedPage |
| }); |
| } |
| |
| } else { |
| this._completeSelectedChanged(oldPage, selectedPage); |
| } |
| }, |
| |
| /** |
| * @param {Object=} oldPage |
| * @param {Object=} selectedPage |
| */ |
| _completeSelectedChanged: function(oldPage, selectedPage) { |
| if (selectedPage) { |
| selectedPage.classList.remove('neon-animating'); |
| } |
| if (oldPage) { |
| oldPage.classList.remove('neon-animating'); |
| } |
| if (!selectedPage || !oldPage) { |
| var nodes = Polymer.dom(this.$.content).getDistributedNodes(); |
| for (var node, index = 0; node = nodes[index]; index++) { |
| node.classList && node.classList.remove('neon-animating'); |
| } |
| } |
| this.async(this._notifyPageResize); |
| }, |
| |
| _onNeonAnimationFinish: function(event) { |
| if (this._squelchNextFinishEvent) { |
| this._squelchNextFinishEvent = false; |
| return; |
| } |
| this._completeSelectedChanged(event.detail.fromPage, event.detail.toPage); |
| }, |
| |
| _notifyPageResize: function() { |
| var selectedPage = this.selectedItem || this._valueToItem(this.selected); |
| this.resizerShouldNotify = function(element) { |
| return element == selectedPage; |
| } |
| this.notifyResize(); |
| } |
| |
| }) |
| |
| })(); |
| </script> |