<!DOCTYPE html>
<html>

  <head>
    <link data-require="bootstrap-css@3.x" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
    <script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script data-require="angular.js@*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
    <script data-require="angular-animate@*" data-semver="1.2.16" src="http://code.angularjs.org/1.2.16/angular-animate.js"></script>
    <script data-require="angular-route@*" data-semver="1.2.16" src="http://code.angularjs.org/1.2.16/angular-route.js"></script>
    <script data-require="underscore.js@*" data-semver="1.6.0" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="animations.css" />
    <script src="script.js"></script>
    <script src="animations.js"></script>
  </head>

  <body ng-app="coursesApp">
    <div class="container">
      <div class="row page-header">
        <h2>Virtual Training</h2>
      </div>
      <div data-ng-view="" id="div-view" class="view-slide-in"></div>
    </div>
    
    <script type="text/ng-template" id="courseDetails.html">
      <div class="thumbnail">
        <div class="caption"><strong>{{course.title}}</strong></div>
        <div ng-show="viewDetails">
          <div style="text-align:center;">{{course.topic}}</div>
          <span  style="margin-right: 9px;">Level: {{course.level}}</span>
          <span class="right">Category: {{course.category}}</span>
          <br />
          <span class="left" style="margin-right: 9px;">Rated: {{course.rating}}/5</span>
        </div>
        <div ng-hide="viewDetails">
          Total Views: {{course.totalViews}} <br />
          Last Week Views: {{course.lastWeekViews}} <br />
        </div>
        <div class="left"><a href="#/course/{{course.id}}">View Course</a></div>
        <div class="right">
          <button class="right btn-link" ng-show="!viewDetails">Details</button>
          <button class="right btn-link" ng-show="viewDetails">Statistics</button>
        </div>
      </div>
      <br />
    </script>
  </body>

</html>
// Code goes here

var app=angular.module('coursesApp',['ngRoute','ngAnimate','courseAnimations']);

app.config(function($routeProvider){
  
  $routeProvider.when('/',{
    templateUrl:'home.html',
    controller:'HomeCtrl'
  })
  .when('/course/:id',{
    templateUrl:'course.html',
    controller:'ViewCourseCtrl'
  });
  
});

app.factory('coursesDataSvc', function(){
  var courses = [
    {
      'id':1, 
      'title':'Introduction to Angular JS',
      'rating':4,
      'numberOfRatings':100,
      'totalViews':1000,
      'lastWeekViews':100,
      'category':'JavaScript',
      'level':'100',
      'topics':[
        'What is Angular JS?',
        'Basics and Data binding',
        'Building blocks',
        'Services, Values and Factories',
        'AJAX and Promises',
        'Routing'
        ]
    },
    {
    'id':2, 
    'title':'Advanced Angular JS',
    'rating':4.5,
    'numberOfRatings':150,
    'totalViews':1200,
    'lastWeekViews':140,
    'category':'JavaScript',
    'level':'300',
    'topics':[
      'Directives',
      'Animations',
      'Unit Testing',
      'End-to-end Testing'
      ]
    },
    {
    'id':3, 
    'title':'ASP.NET MVC Fundamentals',
    'rating':4,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'ASP.NET',
    'level':'200',
    'topics':[
      'Web forms vs MVC',
      'Why MVC?',
      'Model',
      'View',
      'Controller',
      'Going further...'
      ]
    },
    {
    'id':4, 
    'title':'ASP.NET in VS 2013',
    'rating':4,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'ASP.NET',
    'level':'300',
    'topics':[
      'Overview',
      'OWIN and Katana',
      'Updates to Web Forms',
      'Updates to MVC and Razor Views',
      'Web API 2 and OData',
      'Tooling Support'
      ]
    },
    {
    'id':5, 
    'title':'Async in C#',
    'rating':4.2,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'C#',
    'level':'400',
    'topics':[
      'Introduction',
      'Evolution of async with C# and .NET',
      'Task Parallel Library',
      'Using async and await',
      'Patterns and Best Practices'
      ]
    },
    {
    'id':6, 
    'title':'LINQ',
    'rating':3.8,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'C#',
    'level':'200',
    'topics':[
      'C# Language improvements',
      'Basic LINQ Queries',
      'Queries in Lambda Expression Syntax',
      'Deferred and Immediate Execution',
      'LINQ in Layered Applications',
      'Expressions and LINQ to Remote'
      ]
    },
    {
    'id':7, 
    'title':'SQL Server Fundamentals',
    'rating':4.5,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'SQL Server',
    'level':'100',
    'topics':[
      'Overview',
      'Creating tables and constraints',
      'Basic CRUD Operations',
      'Join Queries',
      'Apply, Merge and CTE',
      'Transactions',
      'Query Tuning'
      ]
    },
    {
    'id':8, 
    'title':'ASP.NET Web API OData',
    'rating':3.3,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'ASP.NET',
    'level':'300',
    'topics':[
      'REST and OData',
      'OData in Web API using ODataController',
      'OData using EntitySetController',
      'Consuming OData Services from .NET and JavaScript clients'
      ]
    },
    {
    'id':9, 
    'title':'Trasactions in SQL Server',
    'rating':4.8,
    'category':'SQL Server',
    'level':'400',
    'topics':[
      'Intro to Transact-SQL',
      'Basic Transactions',
      'Transactions in procedures and triggers',
      'Error Handling',
      'Transaction best practices'
      ]
    },
    {
    'id':10, 
    'title':'Intro to Node.js',
    'rating':3,
    'numberOfRatings':100,
    'totalViews':1000,
    'lastWeekViews':100,
    'category':'JavaScript',
    'level':'200',
    'topics':[
      'What is Node.js?',
      'Asynchronous actions and Event loop',
      'Accessing file system',
      'Accessing Databases',
      'Unit testing',
      'Deploying Node.js Apps'
      ]
    }
  ];
  
  function getAllCourses(){
    return courses;
  }
  
  function getCourse(id){
    var filtered = _.filter(courses, function(c){
      return c.id === id;
    });
    return filtered[0];
  }
  
  return {
    getAllCourses:getAllCourses,
    getCourse:getCourse
  };
});

app.controller('HomeCtrl', function($scope, coursesDataSvc){
  $scope.courses = coursesDataSvc.getAllCourses();
});

app.controller('ViewCourseCtrl',function($scope, $routeParams, coursesDataSvc){
  if ($routeParams.id) {
    $scope.course = coursesDataSvc.getCourse(parseInt($routeParams.id));
  }
  else{
    $scope.course = coursesDataSvc.getCourse(1);
  }
});

app.directive('courseDetails', function($animate){
  return {
    scope: true,
    templateUrl:'courseDetails.html',
    link: function(scope, elem, attrs){
      scope.viewDetails = true;
      elem.find('button').bind('click', function(){
        $animate.addClass(elem, "switching", function(){
          scope.viewDetails = !scope.viewDetails;
          scope.$apply();
          elem.removeClass("switching");
        });
      });
    }
  };
});
/* Styles go here */

.view-container {
    position: relative;
}

.view-list {
    margin-top: 1%;
}

.view-list > article h1 {
    font-size: 125%;
    line-height: 120%;
    margin-bottom: 2%;
}

.view-list > article > div > img {
    height: 80px;
    float: left;
    margin-right: 4%;
}

.view-list > article > div > time {
    font-family: "Segoe UI", Arial, Helvetica, sans-serif;
    font-weight: bold;
    float: right;
    margin-left: 2%;
    text-transform: uppercase;
}

.view-list > article > div > address {
    font-family: "Segoe UI", Arial, Helvetica, sans-serif;
    font-size: 95%;
    font-weight: bold;
    margin: 0;
    text-transform: uppercase;
}

.view-list > .article-container-full-width img {
    float: none;
    display: block;
    margin: auto;
}

.view-list > .article-container-full-width address {
    text-align: center;
}

.article-left-content {
    border-bottom: solid 1px rgba(0, 0, 0, 0.08);
    box-shadow: 0 1px rgba(255,255,255,.8);
    min-height: 100px;
    padding: 20px;
}

.article-container-full-width {
    margin: 6px;
    float: left;
    width: 110px;
    height: 140px;
    border-bottom: solid 0 transparent;
    padding: 1.5% .5%;
}

small.right {
    clear: right;
    float: right;
}

#ng-view {
    position: relative;
}

span[data-ng-show] {
    color: #FA787E;
}

.thumbnail {
    padding-bottom: 20px;
    margin: 10px;
    background-color: #DBDBDB;
    height: 150px;
}
.thumbnail .caption {
    text-align: center;
    padding-top: 20px;
    font-family: 'Comic Sans MS';
}
.voting-button {
    cursor: pointer;
    border: none;
    background: none;
}
.right {
    clear: right;
    float: right;
}
<div class="row">
  Filter Courses: <input type="text" ng-model="courseFilter" />
  &nbsp;&nbsp;&nbsp;
  Sort By: <select ng-model="sortExpression">
    <option value="level">Level</option>
    <option value="topic">Topic</option>
    <option value="category">Category</option>
    <option value="rating">Rating</option>
  </select>
  <div class="right"><input type="checkbox" ng-model="showFirstCourses" /> Show First 3 Courses</div>
</div>
<br />
<br />
<div class="row">
  <div data-ng-repeat="course in courses | filter: courseFilter | orderBy: sortExpression" 
       ng-hide="showFirstCourses && $index > 2" class="repeat-animation hide-animation col-md-3">
        
        <div course-details class="det-anim" style="margin-bottom: 2px;" title="{{course.title}}"></div>
    </div>
</div>
<div class="row">
  <h2>{{course.title}}</h2>
  <br />
  <br />
  <div ng-repeat="topic in course.topics">
    <a href="#" onclick="return false;"><i class="glyphicon glyphicon-play"></i></a> <span>{{topic}}</span>
  </div>
  <div class="pull-right">
    <a href="#/">Back to Course List</a>
  </div>
</div>

.det-anim.switching{
  transition: all 1s linear;
  -webkit-transition:all 0.5s linear;
  -moz-transition: all 0.5s linear;
  -o-transition: all 0.5s linear;
  
  position: relative;
  opacity:0.5;
  left:-20px;
}
var courseAppAnimations = angular.module('courseAnimations',['ngAnimate']);

courseAppAnimations.animation('.view-slide-in', function(){
  return{
    enter: function(element, done){
    element.css({
        opacity:0.5,
        position:"relative",
        top:"10px",
        left:"20px"
    })
    .animate({top:0,
              left:0,
              opacity: 1}, 1000,done);
    }
  };
});
  
courseAppAnimations.animation('.repeat-animation', function() {
  return {
    enter : function(element, done) {
      console.log("entering...");
      var width = element.width();
      element.css({
        position:'relative',
        left:-10,
        opacity:0
      });
      element.animate({
        left:0,
        opacity:1
      }, done);
    },

    leave : function(element, done) {
      element.css({
        position:'relative',
        left:0,
        opacity:1
      });
      element.animate({
        left:-10,
        opacity:0
      }, done);
    },

    move : function(element, done) {
      element.css({
        left:"2px",
        opacity:0.5
      });
      element.animate({
        left:"0px",
        opacity:1
      }, done);
    }
  };
});
  
courseAppAnimations.animation('.hide-animation', function() {
  return {
    beforeAddClass : function(element, className, done) {
      if(className == 'ng-hide') {
        element.animate({
          opacity:0
        },500, done);
      }
      else {
        done();
      }
    },
    removeClass : function(element, className, done) {
      if(className == 'ng-hide') {
        element.css('opacity',0);
        element.animate({
          opacity:1
        },500, done);
      }
      else {
        done();
      }
    }
  };
});

courseAppAnimations.animation('.js-anim', function(){
  return{
    beforeAddClass: function(element, className, done){
      if(className == 'switching') {
        element.animate({
          opacity:0
        },1000, function(){
          element.css({opacity:1});
          done();
        });
      }
      else {
        done();
      }
    }
  }
});