• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!--
2@license
3Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7Code distributed by Google as part of the polymer project is also
8subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9-->
10<link rel="import" href="../polymer/polymer.html">
11<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
12<link rel="import" href="../iron-selector/iron-selectable.html">
13<link rel="import" href="neon-animation-runner-behavior.html">
14
15<!--
16Material design: [Meaningful transitions](https://www.google.com/design/spec/animation/meaningful-transitions.html)
17
18`neon-animated-pages` manages a set of pages and runs an animation when switching between them. Its
19children pages should implement `Polymer.NeonAnimatableBehavior` and define `entry` and `exit`
20animations to be run when switching to or switching out of the page.
21
22@group Neon Elements
23@element neon-animated-pages
24@demo demo/index.html
25-->
26
27<dom-module id="neon-animated-pages">
28  <template>
29    <style>
30      :host {
31        display: block;
32        position: relative;
33      }
34
35      :host > ::content > * {
36        position: absolute;
37        top: 0;
38        left: 0;
39        bottom: 0;
40        right: 0;
41      }
42
43      :host > ::content > :not(.iron-selected):not(.neon-animating) {
44        display: none !important;
45      }
46
47      :host > ::content > .neon-animating {
48        pointer-events: none;
49      }
50    </style>
51
52    <content id="content"></content>
53  </template>
54
55</dom-module>
56
57<script>
58(function() {
59
60  Polymer({
61
62    is: 'neon-animated-pages',
63
64    behaviors: [
65      Polymer.IronResizableBehavior,
66      Polymer.IronSelectableBehavior,
67      Polymer.NeonAnimationRunnerBehavior
68    ],
69
70    properties: {
71
72      activateEvent: {
73        type: String,
74        value: ''
75      },
76
77      // if true, the initial page selection will also be animated according to its animation config.
78      animateInitialSelection: {
79        type: Boolean,
80        value: false
81      }
82
83    },
84
85    listeners: {
86      'iron-select': '_onIronSelect',
87      'neon-animation-finish': '_onNeonAnimationFinish'
88    },
89
90    _onIronSelect: function(event) {
91      var selectedPage = event.detail.item;
92
93      // Only consider child elements.
94      if (this.items.indexOf(selectedPage) < 0) {
95        return;
96      }
97
98      var oldPage = this._valueToItem(this._prevSelected) || false;
99      this._prevSelected = this.selected;
100
101      // on initial load and if animateInitialSelection is negated, simply display selectedPage.
102      if (!oldPage && !this.animateInitialSelection) {
103        this._completeSelectedChanged();
104        return;
105      }
106
107      this.animationConfig = [];
108
109      // configure selectedPage animations.
110      if (this.entryAnimation) {
111        this.animationConfig.push({
112          name: this.entryAnimation,
113          node: selectedPage
114        });
115      } else {
116        if (selectedPage.getAnimationConfig) {
117          this.animationConfig.push({
118            animatable: selectedPage,
119            type: 'entry'
120          });
121        }
122      }
123
124      // configure oldPage animations iff exists.
125      if (oldPage) {
126
127        // cancel the currently running animation if one is ongoing.
128        if (oldPage.classList.contains('neon-animating')) {
129          this._squelchNextFinishEvent = true;
130          this.cancelAnimation();
131          this._completeSelectedChanged();
132          this._squelchNextFinishEvent = false;
133        }
134
135        // configure the animation.
136        if (this.exitAnimation) {
137          this.animationConfig.push({
138            name: this.exitAnimation,
139            node: oldPage
140          });
141        } else {
142          if (oldPage.getAnimationConfig) {
143            this.animationConfig.push({
144              animatable: oldPage,
145              type: 'exit'
146            });
147          }
148        }
149
150        // display the oldPage during the transition.
151        oldPage.classList.add('neon-animating');
152      }
153
154      // display the selectedPage during the transition.
155      selectedPage.classList.add('neon-animating');
156
157      // actually run the animations.
158      if (this.animationConfig.length >= 1) {
159
160        // on first load, ensure we run animations only after element is attached.
161        if (!this.isAttached) {
162          this.async(function () {
163            this.playAnimation(undefined, {
164              fromPage: null,
165              toPage: selectedPage
166            });
167          });
168
169        } else {
170          this.playAnimation(undefined, {
171            fromPage: oldPage,
172            toPage: selectedPage
173          });
174        }
175
176      } else {
177        this._completeSelectedChanged(oldPage, selectedPage);
178      }
179    },
180
181    /**
182     * @param {Object=} oldPage
183     * @param {Object=} selectedPage
184     */
185    _completeSelectedChanged: function(oldPage, selectedPage) {
186      if (selectedPage) {
187        selectedPage.classList.remove('neon-animating');
188      }
189      if (oldPage) {
190        oldPage.classList.remove('neon-animating');
191      }
192      if (!selectedPage || !oldPage) {
193        var nodes = Polymer.dom(this.$.content).getDistributedNodes();
194        for (var node, index = 0; node = nodes[index]; index++) {
195          node.classList && node.classList.remove('neon-animating');
196        }
197      }
198      this.async(this._notifyPageResize);
199    },
200
201    _onNeonAnimationFinish: function(event) {
202      if (this._squelchNextFinishEvent) {
203        this._squelchNextFinishEvent = false;
204        return;
205      }
206      this._completeSelectedChanged(event.detail.fromPage, event.detail.toPage);
207    },
208
209    _notifyPageResize: function() {
210      var selectedPage = this.selectedItem || this._valueToItem(this.selected);
211      this.resizerShouldNotify = function(element) {
212        return element == selectedPage;
213      }
214      this.notifyResize();
215    }
216
217  })
218
219})();
220</script>
221