1 <link href=
"../core-selector/core-selector.html" rel=
"import">
3 <link href=
"transitions/hero-transition.html" rel=
"import">
4 <link href=
"transitions/cross-fade.html" rel=
"import">
8 `core-animated-pages` selects one of its children "pages" to show and runs a transition
9 when switching between them. The transitions are designed to be pluggable, and can
10 accept any object that is an instance of a `core-transition-pages`. Transitions to run
11 are specified in the `transitions` attribute as a space-delimited string of `id`s of
12 transition elements. Several transitions are available with `core-animated-pages` by
13 default, including `hero-transition`, `cross-fade`, and `tile-cascade`.
24 background-color: orange;
32 background-color: orange;
42 background-color: blue;
45 background-color: green;
48 // hero-transition and cross-fade are declared elsewhere
49 <core-animated-pages transitions="hero-transition cross-fade">
51 <div id="hero1" hero-id="hero" hero></div>
52 <div id="bottom1" cross-fade></div>
55 <div id="hero2" hero-id="hero" hero></div>
56 <div id="bottom2" cross-fade></div>
58 </core-animated-pages>
60 In the above example, two transitions (`hero-transition` and `cross-fade`) are run when switching
61 between `page1` and `page2`. `hero-transition` transforms elements with the same `hero-id` such
62 that they appear to be shared across different pages. `cross-fade` fades out the elements marked
63 `cross-fade` in the outgoing page, and fades in those in the incoming page. See the individual
64 transition's documentation for specific details.
66 Finding elements to transition
67 ------------------------------
69 In general, a transition is applied to elements marked with a certain attribute. For example,
70 `hero-transition` applies the transition on elements with the `hero` and `hero-id` attribute.
71 Among the transitions included with `core-animated-pages`, script-based transitions such as
72 `hero-transition` generally look for elements up to one level of shadowRoot from the
73 `core-animated-pages` element, and CSS-based transitions such as `cross-fade` look for elements
74 within any shadowRoot within the `core-animated-pages` element. This means you can use
75 custom elements as pages and mark elements in their shadowRoots as heroes, or mark
76 elements in deeper shadowRoots with other transitions.
80 <polymer-element name="x-el" noscript>
89 background-color: blue;
92 <div id="hero" hero-id="bar" hero></div>
96 <polymer-element name="x-page-1" noscript>
105 background-color: orange;
108 <div id="hero1" hero-id="foo" hero></div>
109 <div id="hero2" hero-id="bar" hero></div>
113 <polymer-element name="x-page-2" noscript>
122 background-color: orange;
125 background-color: blue;
130 // The below element is one level of shadow from the core-animated-pages and will
132 <div id="hero1" hero-id="foo" hero></div>
133 // The below element contains a hero inside its shadowRoot making it two levels away
134 // from the core-animated-pages, and will not be transitioned.
139 <core-animated-pages transitions="hero-transition">
140 <x-page-1></x-page-1>
141 <x-page-2></x-page-2>
142 </core-animated-pages>
144 Note that the container element of the page does not participate in the transition.
146 // This does not work
147 <core-animated-pages transitions="cross-fade">
148 <section cross-fade></section>
149 <section cross-fade></section>
150 </core-animated-pages>
153 <core-animated-pages transitions="cross-fade">
155 <div cross-fade></div>
158 <div cross-fade></div>
160 </core-animated-pages>
162 Dynamically setting up transitions
163 ----------------------------------
165 An easy way to dynamically set up transitions dynamically is to use property binding on
166 the transition attributes.
170 <core-animated-pages selected="{{selected}}">
172 <div hero-id="hero" hero></div>
175 <div id="foo" hero-id="hero" hero?="{{selected === 1 || selected === 0}}" cross-fade="{{selected === 2}}"></div>
179 </core-animated-pages>
181 In the above example, the "foo" element only behaves as a hero element if transitioning between
182 `#page1` and `#page2`. It gets cross-faded when transition to or from `#page3`.
187 It is possible to nest core-animated-pages elements for organization. Excessive nesting is
188 not encouraged, however, since it makes setting up the transition more complex.
190 To nest core-animated-pages, the page containing the nested core-animated-pages element should
191 have a `selectedItem` property bound to the `selectedItem` property of the nested element. This
192 will allow the outer core-animated-pages to know which nested page it is actually transitioning
197 <polymer-element name="nested-page" attributes="selectedItem">
199 <core-animated-pages selectedItem="{{selectedItem}}">
201 </core-animated-pages>
205 <core-animated-pages>
206 <section id="page1"></section>
207 <nested-page id="page2"></section>
208 </core-animated-pages>
210 @element core-animated-pages
211 @extends core-selector
216 Fired before a page transition occurs. Both pages involved in the transition are visible when
217 this event fires. This is useful if there is something the client needs to do when a page becomes
220 @event core-animated-pages-transition-prepare
223 Fired when a page transition completes.
225 @event core-animated-pages-transition-end
227 <polymer-element name=
"core-animated-pages" extends=
"core-selector" notap
attributes=
"transitions">
231 <link href=
"core-animated-pages.css" rel=
"stylesheet">
242 'core-transitionend': 'transitionEnd'
246 * A space-delimited string of transitions to use when switching between pages in this element.
247 * The strings are `id`s of `core-transition-pages` elements included elsewhere. See the
248 * individual transition's document for specific details.
250 * @attribute transitions
259 * The last page selected. This property is useful to dynamically set transitions based
260 * on incoming and outgoing pages.
262 * @attribute lastSelected
268 registerCallback: function() {
269 this.tmeta
= document
.createElement('core-transition');
272 created: function() {
273 this._transitions
= [];
274 this.transitioning
= [];
277 transitionsChanged: function() {
278 this._transitions
= this.transitions
.split(' ');
281 _transitionsChanged: function(old
) {
282 if (this._transitionElements
) {
283 this._transitionElements
.forEach(function(t
) {
287 this._transitionElements
= [];
288 this._transitions
.forEach(function(transitionId
) {
289 var t
= this.getTransition(transitionId
);
291 this._transitionElements
.push(t
);
297 getTransition: function(transitionId
) {
298 return this.tmeta
.byId(transitionId
);
301 selectionSelect: function(e
, detail
) {
302 this.updateSelectedItem();
303 // Wait to call applySelection when we run the transition
306 applyTransition: function(src
, dst
) {
307 if (this.animating
) {
308 this.cancelAsync(this.animating
);
309 this.animating
= null;
314 if (this.transitioning
.indexOf(src
) === -1) {
315 this.transitioning
.push(src
);
317 if (this.transitioning
.indexOf(dst
) === -1) {
318 this.transitioning
.push(dst
);
320 // force src, dst to display
321 src
.setAttribute('animate', '');
322 dst
.setAttribute('animate', '');
327 easing
: 'cubic-bezier(0.4, 0, 0.2, 1)'
330 // fire an event so clients have a chance to do something when the
331 // new page becomes visible but before it draws.
332 this.fire('core-animated-pages-transition-prepare');
335 // prepare transition
336 this._transitionElements
.forEach(function(transition
) {
337 transition
.prepare(this, options
);
345 this.applySelection(dst
, true);
346 this.applySelection(src
, false);
349 this._transitionElements
.forEach(function(transition
) {
350 transition
.go(this, options
);
353 if (!this._transitionElements
.length
) {
356 this.animating
= this.async(this.complete
.bind(this), null, 5000);
360 complete: function() {
361 if (this.animating
) {
362 this.cancelAsync(this.animating
);
363 this.animating
= null;
366 this.transitioning
.forEach(function(t
) {
367 t
.removeAttribute('animate');
369 this.transitioning
= [];
371 this._transitionElements
.forEach(function(transition
) {
372 transition
.ensureComplete(this);
375 this.fire('core-animated-pages-transition-end');
378 transitionEnd: function(e
) {
379 if (this.transitioning
.length
) {
380 var completed
= true;
381 this._transitionElements
.forEach(function(transition
) {
382 if (!transition
.completed
) {
387 this.job('transitionWatch', function() {
394 selectedChanged: function(old
) {
395 this.lastSelected
= old
;
396 this.super(arguments
);
399 selectedItemChanged: function(oldItem
) {
400 this.super(arguments
);
403 this.applySelection(this.selectedItem
, true);
407 if (this.hasAttribute('no-transition') || !this._transitionElements
|| !this._transitionElements
.length
) {
408 this.applySelection(oldItem
, false);
409 this.applySelection(this.selectedItem
, true);
413 if (oldItem
&& this.selectedItem
) {
414 // TODO(sorvell): allow bindings to update first?
417 Platform
.endOfMicrotask(function() {
418 self
.applyTransition(oldItem
, self
.selectedItem
);