Ember iPhone style transitions

by amindunited

HTML

<script type="text/x-handlebars" data-template-name="application">
    <div class="titleBar">
        <img src="http://placekitten.com/50/50"/>
        <h1>
            Insert Title
        </h1>
        <img src="http://placekitten.com/50/50"/>
    </div>
    <nav class="mainNav">
        <ul>
            <li>{{#link-to 'index'}}Home{{/link-to}}</li>
            <li>{{#link-to 'blog'}}Blog{{/link-to}}</li>
        </ul>
    </nav>
    <div class="pageWrap">
    {{outlet}}
    </div>
  </div>
</script>

<script type="text/x-handlebars" data-template-name="index">
    <div {{bind-attr class=":page view.current view.previous view.next"}}>
        <h2>Welcome page</h2>
    </div>
</script>


<script type="text/x-handlebars" data-template-name="blog">
    <div {{bind-attr class=":page view.current view.previous view.next"}}>
        <h2>Blog</h2>
        <nav>
            {{#link-to 'post'}}First Article{{/link-to}}
        </nav>
    </div>
    {{outlet}}
</script>
<!--
<script type="text/x-handlebars" data-template-name="blog/index">
    <!--<div {{bind-attr class=":page view.current view.previous view.next"}}>-->
        <!-- <h2>.... Index</h2> -->
<!--    </div>-->
<!--    {{outlet}}
</script>
-->


<script type="text/x-handlebars" data-template-name="post">
    
    <div {{bind-attr class=":page view.current view.previous view.next"}}>
    <h3>POST</h3>
        {{#link-to 'details'}}Details{{/link-to}}
    </div>
    {{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="details">
    <div {{bind-attr class=":page view.current view.previous view.next"}}>
        <h3>Details</h3>
    </div>
    {{outlet}}
</script>


<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/ember.js/1.5.1/ember.min.js"></script>
<script src="https://rawgithub.com/ebryn/ember-model/master/ember-model.js"></script>
<script...

CSS

body {
    padding: 0px;
    margin: 0px;
}
.titleBar {
    background-color: #3d475f;
    color: #FFFFFF;//#6D7A99;//#758099;
    line-height: 50px;
    height: 50px;
}
.titleBar img:first-of-type {
    position: absolute;
    top: 0px;
    left: 0px;
}

.titleBar img:last-of-type {
    position: absolute;
    top: 0px;
    right: 0px;
}

.titleBar > h1 {
    margin:0px;
    padding: 0px;
    text-align: center;
}

.mainNav {
    background-color: #14213E;//#758099;
}
.mainNav > ul { list-style-type:none; height: 38px; margin:0; padding:0;}
.mainNav > ul > li { 
    margin-top: 2px;
    list-style-type:none; 
    height: 35px;
    background-color: #758099;//#6D7A99;//#885258;//#B3B685;//#67694A;
    padding-left: 5px;
    padding-right: 5px;
    float: left;
    line-height: 35px;
    min-width: 15%;
    text-align:center;
    border-left: solid 1px #14213E;
    border-right: solid 1px #3d475f;
}
.mainNav > ul > li:first-of-type { border-top-left-radius: 10px; }
.mainNav > ul > li:last-of-type { border-top-right-radius: 10px; }
.mainNav > ul > li > a { color: #FFFFFF; font-weight: bold; }

.pageWrap {
    position: absolute;
    left: 0%;
    top:90px;
    width: 100%;
    height: 100%;
    border: solid 1px red;
}
/*
Page transitions
*/
.page {
    /*margin-top: 90px;*/
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    position:absolute;
    height: 100%;
    width:100%;
    top: 0px;
    left: 0;
    background-color: rgba(200, 200, 200, .5);

    overflow: auto;
    -webkit-overflow-scrolling: touch;
    -webkit-transform: translate3d(0%, 0, 0);
    transform: translate3d(0%, 0, 0);
}

.page.current {
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
}

.page.previous {
  -webkit-transform: translate3d(-100%, 0, 0);
  transform: translate3d(-100%, 0, 0);
}
 
.page.next {
  -webkit-transform: translate3d(100%, 0, 0);
  transform: translate3d(100%, 0, 0);
}
 
.page.transition {
 ...

JavaScript

/* Request Animation Frame SHIM */
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        function( callback ){
            window.setTimeout(callback, 1000 / 60);
        };
})();

/* Deal with animation event prefixes */
var pfx = ["webkit", "moz", "MS", "o", ""];

function PrefixedEvent(element, type, callback) {
	for (var p = 0; p < pfx.length; p++) {
		if (!pfx[p]) type = type.toLowerCase();
		element.addEventListener(pfx[p]+type, callback, false);
	}
};


App = Em.Application.create();
App.ApplicationView = Em.View.extend({
    current: true,
	previous: false,
	next: false,
});
App.Router.map(function () {
    this.resource('blog', {path:'/blog'}, function(){
        this.resource('post', {path:'/post'}, function(){
//        this.resource('post', {path:':blog_id'}, function(){
            this.resource('details', {path:'/details'}, function(){
            
            });
        });
        
    });
});

App.ApplicationIndexView = Em.View.extend({
 
});

App.PageView = Em.View.extend({
    
    current: false,
	previous: false,
	next: true,
    
	animateIn: function(done){
		console.log("Post view should animateIn");
		this.get('parentView').set('previous', true);
		this.get('parentView').set('next', false);
		this.get('parentView').set('current', false);
		
		var pp = this.get('parentView').$('.page').first();
		pp.addClass('transition');

		console.log("PP!", pp);
        done.call(this);
		
        PrefixedEvent(pp[0], 'transitionEnd', function(e){
			$(e.target).removeClass('transition');
		});
	},
	animateOut: function(done){
		//
		this.set('previous', false);
		this.set('next', true);
		this.set('current', false);
		
		var pp = this.$('.page').first();
		pp.addClass('transition');

		console.log("PP!", pp);

		PrefixedEvent(pp[0], 'transitionEnd',...